Raphael JS Flipping Image - javascript

I have the following code:
image1Rect.animate({
transform: "S-0.025,1"
}, 1000, 'easeOut', function () {
image1Rect.hide();
image1Ref.show();
image1Ref.scale(0.025, 1);
image1Ref.animate({
transform: "S1,1"
}, 1000, 'easeOut');
});
where I am trying to reduce X scale of image1Rect to 0.025 and then when that is done increase the scale X of image1Ref from 0.025 to 1. I am trying to do this using appended transforms but since that did not work for me I had to use deprecated function scale on image1Ref to first reduce its scale X to 0.025.
I would ideally like to do this using appended transforms, could you please help me out?

It is caused by the negative integer in
transform: "S-0.025,1"
Negative integers cause the image to flip in that axis.
use
transform: "S0.025,1"

Try using the matrix as part of the transform:
var R = this.paper;
loop through paths
R.path(blah blah).attr(blah blah).transform("m1,0,0,-1,0,0");
end loop
"m" stands for matrix, and the 4th place "-1" represents the image flip. "1" in that place - (the y-axis place) would be a normal 'as-the-path' dictates, view. Keep in mind you will no longer see your image on the screen, because it has been redrawn well above the containing div. As far as I can tell, it uses the top edge of the div as its pivot.
As an aside, the other places represent some form of 'skew' for the image, which is not interesting if all you want to do is flip it.
To see my image, I had to locate and zoom above it using the viewBox, like this:
R.setViewBox(0,-575,200,200);

Related

How do I scale an svg element with animate?

Similar questions appear to have been asked before, however none of the solutions seem to work for me so here is my code:
this.animate({scale(2, 2, vinerBBoxX, vinerBBoxY)}, 100, mina.easeinout);
vinerBBoxX is the x centre of the element and vinerBBoxY is the y centre, both have worked fine when scaling without animating.
I have had trouble with scaling generally and there are so many solutions on the web that I found completely impenetrable. Please help!
Snap uses its own string format for transforms. s stands for scale, and by default it will scale around its centre.
The attribute to animate is 'transform' as opposes to scale (transform can take scale as a part of a string when set, eg transform: 'scale(2,2)', but this wouldn't work as an animation as it is.
The simplest way is like this...
g.animate({ transform: 's2,4'}, 2000)
You can combine transform elements as well, like
g.animate({ transform: 't200,200s2,4'}, 2000)
In order to translate 't' 200,200 followed by scalex,y 's' 2,4
jsfiddle

Resizing and rotation on svg (Raphael.js) creates jumping

I've been working on this problem for days. I am trying to implement a "free transform" tool for svgs. Similar to that of Raphael.FreeTransform or how you would move/rotate/scale images in MS Word. (Yes, I am aware there are libraries) The following jSFiddle displays my problem: https://jsfiddle.net/hLjvrep7/12/
There are 5 functions in the jsFiddle: rotate-t. shrink-t, grow-t, shrink, grow. The functions suffixed with '-t' also apply the current rotation transformation. e.g.:
grow-t
rect.attr({height : height * 1.25, width : width * 1.25}).transform('r' + degree);
grow
rect.attr({height : height * 1.25, width : width * 1.25});
Once an svg is rotated, then scaled. If you try to rotate the svg again (after scale), the svg jumps. To see this, go top the fiddle:
Hit rotate-t twice. Svg should rotate a total of 30 degrees from the rectangles origin.
Hit grow (not grow-t) twice. Note the top left position of the svg stays the same.
Hit rotate-t once. Note the svg jumps to a different position, then rotates.
Note hitting rotate-t subsequent times will continue to rotate the image around the origin (which is what I want the first time rotate-t is clicked)
One solution I had was to apply the current rotation transformation whenever changing the height and width. This fixes my previous problem, but introduces another problem. To see an example of this, go to the fiddle, and:
Hit rotate-t twice.
Hit grow-t a couple times. Notice the svg grows, but the top left position of the rectangle moves. That's a problem for me. I want the svg to grow without the top left corner to move.
Notes on using the jsFiddle:
Any combination of rotate-t, grow-t, shrink-t will exhibit the ideal rotation behavior (about the origin, no jumping). But this also demonstrates the undesired growing and shrinking (top left position moved when svg is on angle).
Any combination pf rotate-t, grow, shrink will exhibit the ideal scaling behavior (top left corner of svg doesn't move). But this also demonstrates the undesired rotation property (will jump around after different rotations and scales).
Bottom line: I want to be able to the svg rotate around the origin. Then grow the image, while the top left position remains the same. Then rotate the svg again, around the origin without any jumping.
I am aware the how the transform function impacts the local coordinate system of the svg. I'm leaning towards using rotate-t, grow, shrink combo and simply apply some x-y offsets to remove the "jumping" effect. I would imagine there must be some sort of offset I could apply to avoid jumping or shifting during rotation or scaling, but its not clear to me how to calculate such offsets. Any help would be appreciated.
Please don't hesitate to ask anymore questions. Like I said, I've been digging into this for days. Clearly, I don't understand it all, but am somewhat intimate with what's happening and happy to explain anything in more detail.
My solutions for scale, rotate, move back and front etc:
$scope.back = function () {
if($scope.currentImage !==null) {
if($scope.currentImage.prev!=undefined) {
var bot = $scope.currentImage.prev;
$scope.currentImage.insertBefore(bot);
ft.apply();
}
}
};
//Function for moving front
$scope.front = function () {
if($scope.currentImage !==null) {
if($scope.currentImage.next!=undefined) {
var top = $scope.currentImage.next;
if($scope.currentImage.next.node.localName == "image")
$scope.currentImage.insertAfter(top);
ft.apply();
}
}
};
//ZOOM
$scope.zoomIn = function () {
if ($scope.currentImage!= null) {
var ft = paper.freeTransform($scope.currentImage);
if(ft.attrs.scale.y<4) {
$scope.currentImage.toFront();
ft.attrs.scale.y = ft.attrs.scale.y *(1.1);
ft.attrs.scale.x = ft.attrs.scale.x *(1.1);
ft.apply();
ft.updateHandles();
}
}
};

Zoom in and out with jquery/javascript (absolute coordinate not changed)

I use the $(window).resize(function()) to get changes in window size, and acoording to those I want to zoom in and zoom out. Why zooming?!, because I have a lot of dynamically appended divs with absolute coordinate and I want those divs to keep the allignment when window is changed.Basically what one would get, if pressed 'Ctrl' + '-'.
Let's say I have this image
If I use .css to add the following line, which zooms out '-moz-transform': 'scale(0.8)' I get an image like this
But if I use Ctrl + - instead I get
As you see the second image has some coordinates messed up(not changed). Has anyone any idea on why that is, or another function I could use to zoom out?
Here is a jsfiddle to play yourself http://jsfiddle.net/rnhev60f/8/
EDIT:: After the responses, I gave up on the idea. Instead I created a function to calculate the percentage of the changes (newSize / originalSize) and used the percentage to change the position and size of every object in order to avoid all backdoors and bugs. It's a bit more comlicated and ended up with a LOC-wise longer function, but works for me for now. Thanks for the responses tho!
You need to scale both the body and the span
Demo
http://jsfiddle.net/tdov936x/
Code
$('body,span').css({'transform': 'scale(' + currentZoom + ')'});
Result
Consider adding transform-origin: 0% 0%; as 2D transformations can change the x- and y-axis of an element

element upward 100% when transform changed by 1px

I am using css 3d transforms in my project. I am trying to apply a new transform on the containing element of several other elements. I am also trying to use getBoundingClientRect on one of its child elements. That container also has other elements in it. When the container has this value for the transform css property:
translateZ(1026px) rotateX(-90deg) rotateY(180deg) translateZ(439.001px)
here's what element.getBoundingClientRect().top for that certain child element is: 77.953109741210944 according to chrome's developer tools but when I use the elements tab to change the `transform property to this:
translateZ(1027px) rotateX(-90deg) rotateY(180deg) translateZ(439.001px)
here's what element.getBoundingClientRect().top is: -75048.6484375 what would possibly cause this? I'm not posting any code because this occurs even when I modify the values through the console. And when I make the first translateZ something like 1000px, it is still about 77. Even when it is at 0 the top of the bounding rect is about 50-100 somewhere. But when it goes beyond 1026px, the elment seems to jump to top -80000 or so. Visually, however, the element look like it should and doesn't "jump" randomly at 1027px. Can somebody say a situation that might cause this?
in case it is a browser bug or something, I'm using chrome 32.0.1687.2 dev-m Aura
EDIT:
here is a jsfiddle link:
http://jsfiddle.net/a6KxQ/2/
It'll generate a table of all translateZ values and the resulting elt.getBoundingClientRect().top values. The code's messy, but in the outputted table, if you look over it carefully, you'll find that, at some point, the top value will randomly jump far, far down. And then it'll quickly recover to come back to it's previous value. Weird.
The fiddle might take a long time to load.
As you suspected, It has to do with the perspective of the viewpoint. By increasing of the value for the 1st translateZ, you are bringing the rectangle closer to you. Eventually it is so close, it has passed the point of the camera. From that point on, the shape, un-rotated, stood behind your eyes.
Then you did a rotateX(-90deg). what happens there is the rectangle fell down forwards (towards the positive Z direction, but behind the camera.). Now, since the tunnel of the view is of a trapezoid shape, hence you get what we see in this screenshot:
With the rectangle behind the camera, as the it rotates, part of it is pivoted back into view.
So the getBoundingClientRect() is actually giving you the bottom of the shape's bound! Now that the shape is flipped, and it doesn't understand 3D.
I hope that made sense to you. I want to get to you first :) Ask me before down-voting, I can explain in more details.
so, it is by design. You probably want to restrict the translateZ value to be smaller than perspective.
EDIT:
sorry I have been busy. I meant to give a more detailed response. Thanks for whoever gave me the bounty.
A updated demo
Play around the numbers, you will make the following observations:
when translateZ = perspective - 150px, the bounding box is abnormally small and in wrong position
when perspective - 150px < translateZ < perspective + 150px, the bounding box is on the opposite side of where it should be, and the size is abnormally large
when tranlateZ = perspective + 150px, the bounding box is abnormally small again and higher in position in case 1)
the above is not affected by perspective-origin
150px is half of the width/height of the square
when tranlateZ > perspective + 150px, the bounding box is normal again!
Why is that?
in case 1) one of the edges just intersects with the plane that the camera/perspective is located.
in case 2) the square intersects with the camera plane
in case 3) the edge opposite to the edge in case 1) now intersects with camera/perspective plane.
in case 6) all of the square has passed the camera plane
The projection algorithm used to convert 3D coordinates to on screen 2D coodinates does not take into account of the fact that two corners are infront of the camera, and two other corners are behind, hence creating a wrong projection, and hence wrong size.
That was what I meant by "it doesn't understand 3D". That was vague as it can be I realize, Sorry. When all the shape is passed the camera plane, it works again.
Firefox, and Chrome both have this problem, but have different representations, numerically. Probably because different projections matrix are used. So I don't want to figure out what exactly went wrong. Fire a bug report to them :)
Realistically though, you might need to work around it.
I'm not sure how to explain it, and it could be off base, but when you comment out the the perspective css you get the same values down the whole table. I'm not sure what perspective does to the math...
#main3DWrapper{
/*
-webkit-perspective: 1500px;
-moz-perspective: 1500px;
perspective:1500px;
-webkit-perspective-origin: 50% 1%;
perspective-origin:50% 1%;
*/
-webkit-transform: translate3d(0,0,0,0);
transform:translate3d(0,0,0,0);
display: block;
height: 100%;
left: -121.96603393554688px;
position: absolute;
top: 409.5150146484375px;
width: 100%;
}
Also, why are you setting the translateZ() value twice in the js?
container.style.webkitTransform='translateZ('+dist+'px) rotateX(-90deg) rotateY(180deg) translateZ(429.001px)';
container.style.transform='translateZ('+dist+'px) rotateX(-90deg) rotateY(180deg) translateZ(429.001px)';
Shouldn't is just be?:
container.style.webkitTransform='translateZ('+dist+'px) rotateX(-90deg) rotateY(180deg)';
container.style.transform='translateZ('+dist+'px) rotateX(-90deg) rotateY(180deg)';

Kinetic JS: Fading in a fill image when applying it to a polygon shape?

I'm having a play around with Kinetic JS at the moment, with the following example:
http://jsfiddle.net/r8rtJ/4/
var yoda = new Kinetic.Image({
x: 0,
y: 0,
image: imageObj,
width: 106,
height: 118,
scale: 2
});
poly.setFill({
image: imageObj,
offset: {x: 0, y: 0}
});
And i'm wondering if there is a way to fade in the opacity of the image fill once the object has loaded? At the moment it just applies to the polygon instantly, and i can't seem to figure out how to set the opacity of the fill independently from the object itself.
Cheers!
setFill merely tells the polygon object what it should fill itself with when it is supposed to draw itself. This can be image or color.
To set the opacity with which the polygon is drawn, you have the opacity property. What you're trying to achieve can be done by combining a timeout with a function which increases the polygon's opacity and redraws it.
var fadeIn = function(shape) {
var o = shape.getOpacity();
o = o + 0.1 >=1 ? 1 : o + 0.1;
shape.setOpacity(o);
shape.getLayer().draw();
if(o !== 1) {
setTimeout(function() {
fadeIn(shape);
}, 120);
}
};
Example.
EDIT:
There seems to be no way to set the opacity of the fill currently in KinectJS. I've been trying to see if I can find a workaround, though.
One way to do it is, as you mentioned, drawing another polygon with only the stroke and an empty fill over the polygon with the fill, and removing the stroke polygon once the fading in has finished.
Example.
Another way would be to change the drawFunc for the particular polygon.
Whenever a particular layer's draw function is called, drawScene and drawHit functions are called for all its children. drawScene and drawHit functions for Kinetic.Shape call the object's drawFunc. drawScene sets the globalAlpha based on the shape's opacity before calling drawFunc.
The way drawFunc for Kinetic.Polygon is set up is that first, a path is formed on the context for the sides of the polygon. Then it is filled, followed by stroke. The way filling is done is simply setting the fillStyle of the context based on the fill of the polygon, and then context.fill is called.
How is the fill style set with images? When setFill is called for a polygon and the object passed as argument has the property image, fillType is considered to be 'PATTERN'. When the path made by drawFunc is to be filled, a pattern is created using the image and context.createPattern and set as the fill style. Opacity is never considered.
But, we can make a particular polygon consider the fill's opacity by changing its drawFunc with setDrawFunc. I simply copied the drawFunc from KinectJS source and added a condition to fill patterns differently by considering opacity passed with setFill.
Example.
Note that, though, this breaks the mouseover event for some reason. It'd be best to stick to method one until I, or someone else, for that matter, figures out what makes the mouseover not work when drawFunc is changed.
EDIT 2:
I managed to figure it out!
A polygon's drawHitFunc is the same as its drawFunc. So when we change the drawFunc, we end up changing the drawHitFunc which creates problems for when hit detection is required - as is the case with mouseover events.
So, when we change the drawFunc for a polygon, if we also change the drawHitFunc with setDrawHitFunc so that it is the same as the original drawFunc, we avoid breaking the hit-detection.
Example.
yes there's a way to do this. use the transitionTo method to fade the shape opacity like this:
http://www.html5canvastutorials.com/kineticjs/html5-canvas-linear-transition-tutorial-with-kineticjs/
If you want to have a stroke applied, that stays opaque the whole time, you can simply create another shape with a stroke only that sits on top of the shape filled with an image

Categories

Resources