Add easing to the rotation of an image on mouse position - image

Sorry for the English.
I'm trying to add a "ease-out-elastic" movement of rotation, but I can not.
The code on which I am trying is http://jsfiddle.net/22Feh/5/.
Thanks
var img = $('.image');
if(img.length > 0){
var offset = img.offset();
function mouse(evt){
var center_x = (offset.left) + (img.width()/2);
var center_y = (offset.top) + (img.height()/2);
var mouse_x = evt.pageX; var mouse_y = evt.pageY;
var radians = Math.atan2(mouse_x - center_x, mouse_y - center_y);
var degree = (radians * (180 / Math.PI) * -1) + 90;
img.css('-moz-transform', 'rotate('+degree+'deg)');
img.css('-webkit-transform', 'rotate('+degree+'deg)');
img.css('-o-transform', 'rotate('+degree+'deg)');
img.css('-ms-transform', 'rotate('+degree+'deg)');
}
$(document).mousemove(mouse);
}

The easing calculations needs to be done using a timer. This can be complex, however there are many libraries out there that take care of this for you. Take a look at GSAP for starters.
Using your code I've created the jsfiddle below. You can see that all I have done is replace your css code transform code with a TweenMax function and added the ease.
TweenMax.to(img, 1, {rotationZ:degree, ease:Elastic.easeOut});
http://jsfiddle.net/Boolean/PNvgt/
Then if you want to take it a step further there is the GreenSock Draggable library.
http://www.greensock.com/draggable/

Related

I have a question about using turtle graphic functions and looping methods on p5.js

I have to create these two included images using the turtle function and the loop method on p5js and I am struggling I was given https://editor.p5js.org/dpapanik/sketches/_lbGWWH6N this code on p5js as a start please help, thanksenter image description here
So I've played around with some of the stuff for awhile, and I've created two functions. One that makes a single quadrant of the first problem, and one that creates a single wiggly line for the second problem. This is just a base for you to work of in this process. Here's each of the functions. Also, note that each of them takes in the turtle as a parameter:
function makeLineQuadrant(turtle) {
// this currently makes the top left corner:
let yVal = windowWidth * 0.5;
let xVal = windowWidth * 0.5;
for (let i = 0; i < 13; i++) {
// loop through the 12 lines in one quadrant
turtle.face(0); // reset for the new round
turtle.penUp();
let startLeft = i * ((windowWidth * 0.5) / 12); // decide which component on the button we should start at
let endTop = (12 - i) * ((windowWidth * 0.5) / 12); // how far down the y-axis should we go? You should write this out on paper to see how it works
turtle.goto(startLeft, yVal);
turtle.penDown();
let deg = turtle.angleTo(xVal, endTop); // what direction do I need to turn?
turtle.face(deg);
let distance = turtle.distanceTo(xVal, endTop); // how far away is it?
turtle.forward(distance);
}
}
I tried to add a few comments throughout, but if there is any step that is confusing, please add a comment.
function makeSquiggle(turtle) {
turtle.setColor(color(random(0, 255), random(0, 255), random(0, 255)));
let middleX = windowWidth * 0.5, middleY = windowHeight * 0.5;
turtle.goto(windowWidth * 0.5, windowHeight * 0.5);
// let's start moving in a random direction UNTIL our distance from the center is greater than some number X
let X = 300; // arbitrary distance from center
// some variables that can help us get some random movement for our turtle:
let turtleXvel = random(-3, 3), turtleYvel = random(-3, 3);
while (turtle.distanceTo(middleX, middleY) < X) {
turtle.face(0);
// calculate movement:
let newXmove = turtle.x + turtleXvel, newYmove = turtle.y + turtleYvel;
// direct our turtle:
turtle.face(turtle.angleTo(newXmove, newYmove));
let distance = turtle.distanceTo(newXmove, newYmove); // how far away is it?
// move our turtle
turtle.penDown();
turtle.forward(distance);
// change the velocity a little bit for a smooth curving:
turtleXvel += random(-1, 1);
turtleYvel += random(-1, 1);
}
}
Note that I'm changing the velocities instead of the position directly. This is a classic Calculus / Physics problem where the derivative gives us a smaller range, so adjusting turtleXvel and turtleYvel change the position in much less drastic ways versus:
turtle.x += random(-1, 1);
turtle.y += random(-1, 1);
You should look at the difference as well to visualize this. Beyond this is working with these structural components to finish this up!

Custom scale in d3

There are lots of scale functions in d3 (e .g.: d3.scale.linear(), d3.scale.sqrt(), d3.scale.log(), ...). But for a specific situation I need a different scale function (to be precise "generalised logistic function"). Is there any way to define a custom scale function in d3? Like
function d3.scale.mycustom() {
...
}
It is easy from a mathematical point of view, but how do I implement this in d3?
With the hint of Enche, I tried the following:
var my_custom_scale = function interpolate(t) {
var A = 0;
var K = 1;
var B = 10;
var NU = 0.7;
var Q = 0.5;
var C = 1;
return A + (K - A) / Math.pow(C + Q * Math.exp(-1 * B * (t - 0.5)), 1 / NU);
}
Which works:
console.log(my_custom_scale(0.0)); // 0.0021
console.log(my_custom_scale(0.1)); // 0.0084
console.log(my_custom_scale(0.2)); // 0.0324
console.log(my_custom_scale(0.3)); // 0.1098
console.log(my_custom_scale(0.4)); // 0.2934
console.log(my_custom_scale(0.5)); // 0.5603
console.log(my_custom_scale(0.6)); // 0.7857
console.log(my_custom_scale(0.7)); // 0.9107
console.log(my_custom_scale(0.8)); // 0.9655
console.log(my_custom_scale(0.9)); // 0.9871
console.log(my_custom_scale(1.0)); // 0.9952
But how do I now make this available as d3.scale.my_custom_scale?
That Wikipedia article is a little overwhelming to me to write the actual code, but:
Is there any way to define a custom scale function in d3?
Yup! See here. You might want/need to use an interpolator, which you'll see referenced on the quantitative scales page often.

Moving a body to a specific position

I understand that I can use body.position.set(x, y, z) to instantaneously move a body, but how can I move it smoothly in an animated manner where it's movement will adhere to the physics and collide with any other bodies on its journey? Using body.velocity.set(x, y, z) will set its velocity, and using body.linearDamping = v, will provide some friction/resistance... but it's still not good enough to allow me to specify exactly where I want the body to stop.
It sounds like you're looking for a kinematic body. With kinematic bodies, you have full control over the movement, and it will push away other bodies in its path. However, the body has infinite mass and is not affected by other bodies colliding with it.
Start off by defining the start and end positions of your body.
var startPosition = new CANNON.Vec3(5, 0, 2);
var endPosition = new CANNON.Vec3(-5, 0, 2);
var tweenTime = 3; // seconds
Then create your kinematic body. In this example we'll add a Box shape to it.
var body = new CANNON.Body({
mass: 0,
type: CANNON.Body.KINEMATIC,
position: startPosition
});
body.addShape(new CANNON.Box(new CANNON.Vec3(1,1,1)));
world.add(body);
Compute the direction vector and get total length of the tween path.
var direction = new CANNON.Vec3();
endPosition.vsub(startPosition, direction);
var totalLength = direction.length();
direction.normalize();
The speed and velocity can be calculated using the formula v = s / t.
var speed = totalLength / tweenTime;
direction.scale(speed, body.velocity);
For each update, compute the tween progress: a number between 0 and 1 where 0 i start position and 1 is end position. Using this number you can calculate the current body position.
var progress = (world.time - startTime) / tweenTime;
if(progress < 1){
// Calculate current position
direction.scale(progress * totalLength, offset);
startPosition.vadd(offset, body.position);
} else {
// We passed the end position! Stop.
body.velocity.set(0,0,0);
body.position.copy(endPosition);
}
See full code below. You can duplicate one of the cannon.js demos and just paste this code.
var demo = new CANNON.Demo();
var postStepHandler;
demo.addScene("Tween box",function(){
var world = demo.getWorld();
// Inputs
var startPosition = new CANNON.Vec3(5, 0, 2);
var endPosition = new CANNON.Vec3(-5, 0, 2);
var tweenTime = 3; // seconds
var body = new CANNON.Body({
mass: 0,
type: CANNON.Body.KINEMATIC,
position: startPosition
});
body.addShape(new CANNON.Box(new CANNON.Vec3(1,1,1)));
world.add(body);
demo.addVisual(body);
if(postStepHandler){
world.removeEventListener('postStep', postStepHandler);
}
// Compute direction vector and get total length of the path
var direction = new CANNON.Vec3();
endPosition.vsub(startPosition, direction);
var totalLength = direction.length();
direction.normalize();
var speed = totalLength / tweenTime;
direction.scale(speed, body.velocity);
// Save the start time
var startTime = world.time;
var offset = new CANNON.Vec3();
postStepHandler = function(){
// Progress is a number where 0 is at start position and 1 is at end position
var progress = (world.time - startTime) / tweenTime;
if(progress < 1){
direction.scale(progress * totalLength, offset);
startPosition.vadd(offset, body.position);
} else {
body.velocity.set(0,0,0);
body.position.copy(endPosition);
world.removeEventListener('postStep', postStepHandler);
postStepHandler = null;
}
}
world.addEventListener('postStep', postStepHandler);
});
demo.start();
You need to use a physics library for this, such as Physijs. It works easily with Three.js. Googling for "Physijs Three.js" will provide examples.

threejs modify envMap on mouseover

Im new in threejs, I want to learn some about this library... but, in my opinion, there is very little documentation.
Issue is:
I have a SphereGeometry and I want to give It some interactivity through mouse events, I'm using three.domevent.object3d.js for "mouseover" and "mouseout" events to make scale property bigger or smaller. But I can not to modify sphere material when mouseover is triggered because nothing happens. My code is:
sphere.on('mouseover', function(event){
event.target.scale.x *= 2;
event.target.scale.y *= 2;
event.target.scale.z *= 2;
event.target.material.envMap = textureCube;
event.target.material.combine = THREE.MixOperation;
event.target.material.reflectivity = 0.15;
}).on('mouseout', function(event){
event.target.scale.x *= 0.5;
event.target.scale.y *= 0.5;
event.target.scale.z *= 0.5;
event.target.material.envMap = null;
event.target.material.combine = THREE.MixOperation;
event.target.material.reflectivity = 0;
});
textureCube is a bunch of jpegs for skyboxMesh, its code is:
var r = "images/";
var urls = [ r + "px.jpg", r + "nx.jpg",
r + "py.jpg", r + "ny.jpg",
r + "pz.jpg", r + "nz.jpg" ];
textureCube = THREE.ImageUtils.loadTextureCube( urls );
Any help will be appreciated
Thanks
If you want to add or remove an environment map from a material, you will have to add
material.needsUpdate = true;
Have a look at the "How to update things" doc: https://threejs.org/docs/index.html#manual/en/introduction/How-to-update-things
three.domevent.object3d.js is not part of the library, so I can't comment on that.
three.js r.52

Smart Centering and Scaling after Model Import in three.js

Is there a way to determine the size and position of a model and then auto-center and scale the model so that it is positioned at the origin and within the view of the camera? I find that when I import a Collada model from Sketchup, if the model was not centered at the origin in Sketchup, then it is not centered in three.js. While that makes sense, it would be nice to auto-center to origin after importing.
I've seen some discussion in the different file loaders about getting the bounds of the imported model, but I have been unable to find any references to how to do that.
The scaling issue is less important, but I feel like it relates to a bounds function, which is why I asked it too.
EDIT:
More info after playing around a bit and a few more google searches...
The code for my callback function on loading the collada file now looks like this:
loader.load(mURL, function colladaReady( collada ) {
dae = collada.scene;
skin = collada.skins[ 0 ];
dae.scale.x = dae.scale.y = dae.scale.z = 1;
dae.updateMatrix();
//set arbitrary min and max for comparison
var minX = 100000;
var minY = 100000;
var minZ = 100000;
var maxX = 0;
var maxY = 0;
var maxZ = 0;
var geometries = collada.dae.geometries;
for(var propName in geometries){
if(geometries.hasOwnProperty(propName) && geometries[propName].mesh){
dae.geometry = geometries[propName].mesh.geometry3js;
dae.geometry.computeBoundingBox();
bBox = dae.geometry.boundingBox;
if(bBox.min.x < minX) minX = bBox.min.x;
if(bBox.min.y < minY) minY = bBox.min.x;
if(bBox.min.z < minZ) minZ = bBox.min.z;
if(bBox.max.x > maxX) maxX = bBox.max.x;
if(bBox.max.y > maxY) maxY = bBox.max.x;
if(bBox.max.z > maxZ) maxZ = bBox.max.z;
}
}
//rest of function....
This is generating some interesting data about the model. I can get an overall extreme coordinate for the model, which I'm assuming (probably incorrectly) would be close to an overall bounding box for the model. But trying to do anything with those coordinates (like averaging and moving the model to the averages) generates inconsistent results.
Also, it seems inefficient to have to loop through every geometry for a model, is there a better way? If not, can this logic be applied to other loaders?
You can use THREE.Box3#setFromObject to get the bounding box of any Object3D, including an imported model, without having to loop through the geometries yourself. So you could do something like
var bBox = new THREE.Box3().setFromObject(collada.scene);
to get the extreme bounding box of the model; then you could use any of the techniques in the answers that gaitat linked in order to set the camera position correctly. For instance, you could follow this technique (How to Fit Camera to Object) and do something like:
var height = bBox.size().y;
var dist = height / (2 * Math.tan(camera.fov * Math.PI / 360));
var pos = collada.scene.position;
camera.position.set(pos.x, pos.y, dist * 1.1); // fudge factor so you can see the boundaries
camera.lookAt(pos);
Quick fiddle: http://jsfiddle.net/p19r9re2/ .
try geometry.center()
center: function () {
var offset = new Vector3();
return function center() {
this.computeBoundingBox();
this.boundingBox.getCenter( offset ).negate();
this.translate( offset.x, offset.y, offset.z );
return this;
};
}(),

Resources