Skip to content

Added Transformation Support #148

Open
wants to merge 4 commits into from

3 participants

@Hackwar
Hackwar commented Jun 19, 2011

Hi Jason,
in this commit I again tried to implement transformation support and succeeded pretty much. It now supports matrix, skew, scale and rotate. So far the translation is still missing, which seems to be due to an error in my translation algorithm. This is also the reason, why its not rotating around the correct transformation origin. This is still something that needs to be fixed to have this working. But I thought, commit early, commit often... :-)

The supported code would be:
transformation: skew(30px) rotate(20deg) scale(1.2);

Maybe you have an idea for the translation?

@lojjic
Owner
lojjic commented Jun 19, 2011

I've only looked at this briefly but it looks like a good start! Thanks for spending time on this. :)

Nothing jumps out at me right away with the translate issue, I'll try to take a closer look soon.

Have you thought about how to handle transforming the rendering elements for other PIE effects like border-radius and box-shadow? Currently the element foreground gets transformed but the box stays in place. Matrix transforms can be done on VML without quality loss (see the 'skew' element) but it's a bit difficult.

If you haven't already you might take a look at the 'transforms' branch in GitHub, I started on some of this same stuff a while ago, don't really remember how far I got or if it'll help at all.

@Hackwar
Hackwar commented Jun 19, 2011

I thought maybe to simply just apply the filter to the VML element, too... :-) I haven't tried that though. I didn't know how to select the VML that belongs to the targetelement. Regarding the translation: I think the only way that is going to work is calculating all this by hand and moving the element around by positioning it absolute. The translate function of the MS filter does not seem to work right... I'll see what I can come up with.

@lojjic
Owner
lojjic commented Jun 19, 2011

You can get a reference to the css3-container element from within your TransformRenderer like so:

this.parent.getBox()

Go ahead and try applying the matrix filter to that element, but I think you'll find that it will first make all semi-transparent pixels fully opaque, which will look awful on e.g. the antialiasing of rounded corners and the opacity gradient of box-shadow. I could be wrong though. :)

@lojjic
Owner
lojjic commented Jun 19, 2011

Regarding the translate shifting, I've found this article by Brendan Kenny helpful: http://extremelysatisfactorytotalitarianism.com/blog/?p=922

@Hackwar
Hackwar commented Jun 20, 2011

It looks like we might be able to apply the same matrix to the VML elements like to the filter. Lets see how we can implement all of this. ;-)

@Boss32
Boss32 commented Jun 23, 2011

PIE.JS with IE 7-8 not working.

@Hackwar
Hackwar commented Jun 24, 2011

I see why you didn't implement transform yet. Its a $%§# to do. Still working on this.

@Hackwar
Hackwar commented Jun 24, 2011

Let me describe what I've tried so far and maybe someone can help me.
1. I've added your matrix class from your transform branch to my code.
2. I'm parsing the transform CSS and apply it to the matrix so that I got my skewed, scaled and rotated matrix.
3. Then I'm adding the filter to the original HTML element. All fine so far.
Now comes the difficult part:
4. I think the getBoxPath() function from RendererBase is the point to solve the issue of applying the transformation to the elements created by PIE. So I calculate the start and ending points of the straight lines in case of rounded corners and the radii of the corners.
5. With that information I'm calculating two control points for each corner to draw a bezier curve from the end of a line to the start of the next one.
6. Then I send all of this through my transformation matrix and then render the VML accordingly.

From my limited understanding, this should allow us to skew a box without a problem, since the control points would also be properly transformed and thus we would have the whole thing solved. Even with two different radii for the X and Y axis... But of course its not working... And I don't have the slightest clue why that is the case.

@lojjic
Owner
lojjic commented Jun 24, 2011

LOL no kidding, it's a pain for sure. :)

I've played around a bit in the past with the VML 'skew' element:
http://msdn.microsoft.com/en-us/library/bb229470%28v=vs.85%29.aspx

This seems to basically do what you're trying to do (transform each of the points of the box path and keep the curves angled correctly) but should be easier than messing with beziers. There's a catch though (and this is something you'd run into with your approach anyway): it transforms the path, but does not transform the fill. This means that background images and gradients will stay at their original size and position!

How do we fix this? I'm not sure I have a 100% answer, but here's what I've been thinking:
1) Scaling can be handled pretty easily just by changing the size of the gradient or bg image
2) Rotation can be handled via the 'rotation' CSS property: http://msdn.microsoft.com/en-us/library/bb263877%28v=VS.85%29.aspx -- I tested this and it does seem to work on VML elements and brings the image or gradient fill along with the rotation. But if you apply rotation this way then you'll have to remove that amount of rotation from your matrix.
3) Other transforms (skew) I'm not sure about. For gradients you might be able to adjust the angle and length of the gradient to match the skew. For images... I don't know, maybe in this case we fall back to applying the matrix as a filter (just to the VML element showing the image) and we document the side effects that brings?

(A lot of this requires decomposition of the matrix into its constituent transforms (scale, rotate, skew) and incidentally that's the reason that in my branch the TransformStyleInfo maintains the original individual transform instructions in addition to the combined matrix.)

Let me know if you come up with any better ideas. Fun fun fun! :)

@Hackwar
Hackwar commented Jun 24, 2011

After finding some bugs, its more or less rendering most of this stuff correctly now in the sense that a box now has four corners and that they are somewhat roundish. Working with the bezier curves showed a different issue. A border-radius of 50px looked good, but a radius of 5px just didn't create a real curve...

I'm gonne keep on trying here. :P

@Hackwar
Hackwar commented Jul 8, 2011

I just made another commit. This is really not a nice feature to implement... maybe I should look for something easier, like animations or something. ;-)

So, neither using the quarter circles nor the bezier curves was the solution for me so far... Right now I'm describing an elipse that is creating a correct quarter circle and it even seems as if it would behave together with skew correctly... :-) However the starting and end point of the curves are not correct yet and I'm still not accounting correctly for the displacement that IE is creating and the rotation origin. Still a lot of work, but I'm getting closer...

@Hackwar
Hackwar commented Jul 9, 2011

This is the theory where I am right now and what I implemented so far, but it doesn't work... Anyway, here it goes:

I got the start and end points of each side of the box to the respective end of the quarter circle of the corners. I'm drawing a shape along that path, where I use the VML function clockwisearcto to draw a quarter circle to have those fancy rounded corners. That was working pretty well with the Hackwar/PIE@7ca7672 commit. If we were just talking about rotation, all of this wouldn't be such a big issue, but we also got the skew transformation, which changes the radius of the corners. This means, we have to recalculate the center of the corners circle and its radius to calculate the correct box for the clockwisearcto function. Fortunately, we got those two points where the lines of the two sides almost meet and between which we want to draw parts of a circle. Thos points are on the radius of our circle and the sides of our elements box describe tangents to that circle. By doing a Gram-Schmidt-process, we get orthogonal lines that run through those two endpoints and then through the center of our corner circle. So I calculate the meeting point of those two lines and by calculating the distance between one endpoint and the center, I got the radius. Then I can describe a box around the corner that should make VML draw the right rounded corner. but as often, its doing everything but the stuff that I was expecting... :-)

Maybe you got an idea? If this is solved, the next issue would be the actual size of the box and positioning all those elements correctly over each other, still the issue of the rotation origin and when you are scrolling the page, the VML element sticks to the viewport... :-)

@lojjic
Owner
lojjic commented Jul 9, 2011

Sounds like quite the rabbit hole!

Did you try the VML 'skew' element? I believe it handles the corner curves correctly. Something like the following seems to give a properly skewed/rotated/scaled shape (with the gradient/image fill caveats I mentioned earlier):

<v:shape coordsize="408,208" coordorigin="1,1" path=" m2,32 qy32,2 l376,2 qx406,32 l406,176 qy376,206 l32,206 qx2,176 x e" stroked="true" filled="false"
    style="POSITION: absolute; WIDTH: 204px; HEIGHT: 104px; TOP: 0px; LEFT: 0px">
  <v:fill type="solid" color="white" color2="white" colors="" opacity="1" src="" position="0,0" angle="0" method="any" focusposition="0,0" focussize="0,0" />
  <v:stroke color="#00c" weight="1.5" dashstyle="solid" linestyle="single" />
  <v:skew on="t" origin="0,0" matrix="1 .5 .2 1.5 0 0" />
</v:shape>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.