How can I determine the current transform that's being applied by an html5 canvas.
It seems that it only supports two methods for dealing with transforms "transform", "setTransform" but I can't seem to discover the results of applying the transforms.
Short of tracking them all myself and duplicating the the matrix mathematics that it must be doing natively, how can I figure out the current transform?
I've made a wrapper which adds this method to Canvas.
http://proceduralgraphics.blogspot.com/2010/03/canvas-wrapper-with-gettransform.html
Firefox's Canvas 2D contexts have (non-standard) mozCurrentTransform and mozCurrentTransformInverse properties.
The WhatWG have now defined currentTransform and currentTransformInverse properties (the former even being writable). Here's the relevant part of the spec:
http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#transformations
However these probably won't be universally implemented in browsers for some time yet, so if you want portability you will have to fall back to tracking the matrix manually as #Dave and #James say.
Every man and his dog seems to have written such a Canvas-transform-matrix-tracker. I just had a look at #Dave Lawrence's one; I think mine is better in a few ways, even though I'm sure it's also inferior in other ways.
Mine doesn't require any changes to user JS code - it modifies the Canvas and context prototypes, so you just add a
script
tag and you're good to go.
It intercepts setting of the currentTransform property.
It tries hard only to do what it needs to do.
It works in latest Chrome and Firefox, but I haven't tested it in IE yet.
I put mine in a jsfiddle, with a simple demonstration:
http://jsfiddle.net/XmYqL/1/
Here is a code block to placate stackoverflow so it lets me link to jsfiddle (??):
code, code, wonderful code
I finally got around to uploading my polyfill to GitHub:
https://github.com/supermattydomain/canvas.currentTransform.js
I know it's not perfect, but I'd really like to see us all work together on implementing One True Solution to this problem. I don't care if it's mine or someone else's. This corner of JavaScript/HTML5/Canvas is too much like the Balkans: a sea of partial solutions.
Please, everybody, fork mine, add your changes and send me pull requests, or send me your URL so I can merge your code in, or replace mine wholesale with yours, or whatever.
This is a stupid problem that I just want to nail. If we work together we can do it.
You can look here for the functions that affect transformation:
http://www.whatwg.org/specs/web-apps/current-work/multipage/the-canvas-element.html#transformations
If you use the setTransform function, then the current transform matrix is set to the identity matrix, then it uses what was set.
At that point you have the current transform matrix.
Now, if you are going to reset it, then start to call the other transformation methods, if you need to know what it is, it is easy to do the math to calculate the transformation matrix, so just do the operations, using your own transformation functions, then you can set the transform, as you have calculated it.
If you can't do that, then you are currently out of luck, but this post also has the same problem, so you may want to petition to have a new function added, getTransform.
http://forums.whatwg.org/viewtopic.php?t=4164
Although not a solution for how to get the current transform, it may be an useful fact that contexts include a save() and a restore() function that can be used to push and pop context state, including the current transformation matrix.
(At least it may benefit those, who, similarly to me, were looking for getTransform in order to implement a stack using it...)
Related
I have converted the MD2 code from the library to use THREE.BufferGeometry instead of THREE.Geometry to vastly improve memory footprint. To do this I just convert the model to THREE.BufferGeometry after it is done loading. I also had to modify the MorphBlendMesh code to use attributes for the morphTargetInfluences.
This is working great except for issue: the shadows don't update during animation, it always uses the shadow from the first frame of the animation.
I haven't seen any documentation on morphTargetInfluences attributes, so I don't have much to go on.
I can't really post the code since it is too much spread out across the code base.
I am just hoping that someone out there might have some insight as to how shadows get updated during morph animation, and maybe point me in the right direction on how to research this issue.
I have found the problem, and a workaround!
The code in the shader renderer is checking to see if geometry.morphTargets has a non-zero length before it decides to set the 'usemorphing' flag. The converted buffergeometry does not have a .morphTargets field since this information appears to have moved to .morphAttributes for buffergeometries.
My hack workaround is to add a fake .morphTarget list like so:
Buffergeometry.morphTargets = [];
Buffergeometry.morphTargets.push(0);
From looking at the code, it seems that three does not give much control over the depthFunc. I would like to confirm that it's only set once as the default GL state, and not available say, in the material?
I'm not familiar with all examples, and was wondering if this is happening somewhere?
If not, what would be the best approach to set the depthFunc to gl.EQUAL for example, when a specific draw call is being made i.e. a mesh with a material?
Is something like toggling between scenes i.e. use one to render stuff, then use another one to render stuff on top of the first one a good solution for this? That's the only example that i've seen of tweaking the otherwise sorted objects.
It's currently in the dev branch of three.js: the pull request.
The following answer shows that matrix transform functions are faster then regular transform:
https://stackoverflow.com/a/20892177/157397
That sounds logical to me because the browser will translate transform functions into a matrix anyway.
I am writing a JS Class that renders objects using CSS. In order to be more usable for anyone, I would like to use understandable attributes (the same used in the separate transform functions):
http://codepen.io/meodai/pen/gCbrt
The thing is I would have to calculate the values for the matrix with JS. I would like to know if it is faster to let the browser handle it (like it is now), or should my class calculate a matrix? What would be faster in the end?
Well, first of all, as Seldaek says, don't try to beat the browser on performance, unless there is a real issue.
Second, most of the time, the key issue in performance is rendering, not parsing the value of the property. That would be only noticeable if you are changing your values really fast. And, in that case, probably the easy way to optimize it is to change the transform less often. And leave the smoothing to the browser, via some transition.
And third, you can hit unexpected issues. to say one, the matrices for a 0deg rotation and a 360deg rotation are the same. However, when you are at 359 deg, it's not the same to change that to 360deg than to 0deg. The browser somehow preserves the rotation state here; and you will have problems handling that working only with matrices.
I would not try to beat the browser at the performance game unless you really detect an issue. It's likely they optimize more than you would already, and if not then they might in the future.
I'd like to be able to write an application in HTML5 that is similar to the following.
HTML5 Canvas Animals on the Beach Game with KineticJS
The problem with that demo though is the mouse over event is only accurate to the rectangle surrounding the animal. Is there any way to do this with more accuracy, be it in KinectJS or otherwise?
There are generally two ways:
Using custom paths with each image as hitboxes (that you manually define) then using an is-point-in-path algorithm
Using a ghost-canvas (or whatever you like to call it) as I detailed in this old tutorial. Ignore the link to the new tutorial, the old one uses what you'd want.
The first method here is much faster but requires a lot more code and manual work. The second method is pixel-perfect but much slower. Still, if you don't have an enormous amount of objects it may suit your needs.
I´m working with Raphael, and I think that I´m using it in a way that does not take advantage of some features that seems to be useful.
For example, I´m trying to add a listener on a Set (a group of elements), in a way that on mouse over on any of those elements, the script triggers an animation on the whole set.
When you add a listener to a set, Raphael adds the listener to each of the elements and animates them separately.
Like you see in this example http://jsfiddle.net/4VYHe/3/ in wich I want that all the rectangles in the same set (set = horizontal groups of 10 rectangles), change the color attribute on mouse over on any of them.
I have found a few methods in the raphael documentation that i think must help to achive this. But I´m having a hard time understanding how these methods work.
For example:
the eve object(http://raphaeljs.com/reference.html#eve)
the Element.animateWith() method (http://raphaeljs.com/reference.html#Element.animateWith)
the Raphael.animation() method (http://raphaeljs.com/reference.html#Raphael.animation)
The Raphael Library seems to be really powerful and I really want to get it work properly, I don´t want to write all kinds of diferent javascript hacks, because I think that these tools have to get the work done in a more elegant way.
If you think that I´m using the wrong library I´m still open to all kinds of advices.
Thank you in advance.
---EDIT---
This is a working example (http://jsfiddle.net/4VYHe/6/). But this is a hack with lack of efficiency and elegancy. I want something that uses the correct tools on the correct way.
There is some information on this page. http://www.irunmywebsite.com/raphael/additionalhelp.php?v=2#PAGETOP . A couple of examples, but nothing that explain how things work in Raphael.
Take a look at this fiddle, I think it is doing what you are looking for. The fundamental difference is that you want to call animate on the set, rather than this. It appears that when you add a handler to a set, this refers to the individual elements in the set (which are iterated over to assign the handler), and not the set itself.
Note that I pulled the handler functions out into the getHoverHandler function:
function getHoverHandler(fillColor) {
var cSet = set;
return function(){
cSet.animate({fill: fillColor}, 300);
};
}
set.hover(getHoverHandler('#000'),
getHoverHandler('#FFF'));
in order to break the closure. If you try to do it like this:
set.hover(function(){
set.animate({fill: '#000'}, 300)
}, function(){
set.animate({fill: '#FFF'}, 300)
});
as you loop through, set will keep changing, and the closures will maintain awareness of this. As a result, all handlers will be acting on the last row of boxes.
If you don't understand javascript closures, you might want to look at this article. It is old, but in pretty simple language, and it helped me as I have tried to get my head around them.
Kreek is absolutely correct in this comment above. Sets are a workaround for the inconsistencies between SVG and VML.
In your example above, you're running into the same issue that you were facing in your previous question. Using this in an anonymous function will almost always not work in the way you expect, as this won't be referring to what you think it is. Have a look at this discussion, particularly the first two comments in the comments section. (As an aside, the commenter uses "self" as the reference to "this", which is much better than my "that", which goes to show there's always someone doing it better than yourself)
Anyway, with that in mind, I've cloned your fiddle, wrapped your set in an object, and put the events into the object constructor. By doing this, the event can then refer to that.set and animate all objects in the set at the same time.
It's a small but fundamental concept that will aid you throughout any Raphael (or javascript) development you do.
This doesn't answer your question directly, but hopefully clarifies some of the issues you seem to be discovering. I can't really comment on the animation calls you've mentioned, but I do think that Raphael as a library is definitely worth persevering with.
N.