I am looking for a way to implement the exact functionality from this answer using angularjs: Specifically, for a box (div) to move randomly around a screen, while being animated. Currently I have tried
myApp.directive("ngSlider", function($window) {
return {
link: function(scope, element, attrs){
var animateDiv = function(newq) {
var oldRect = element.getBoundingClientRect();
var oldq = [oldRect.top, oldRect.left];
if (oldq != newq){
var dir = calcDir([oldq.top, oldq.left], newq);
element.moveTo(oldq.left + dir[0], oldq.top + dir[1]);
setTimeout(animateDiv(newq), 100);
}
};
var makeNewPosition = function() {
// Get viewport dimensions (remove the dimension of the div)
var window = angular.element($window);
var h = window.height() - 50;
var w = window.width() - 50;
var nh = Math.floor(Math.random() * h);
var nw = Math.floor(Math.random() * w);
return [nh,nw];
};
function calcDir(prev, next) {
var x = prev[1] - next[1];
var y = prev[0] - next[0];
var norm = Math.sqrt(x * x + y * y);
return [x/norm, y/norm];
}
var newq = makeNewPosition();
animateDiv(newq);
}
};
});
There appears to be quite a bit wrong with this, from an angular point of view. Any help is appreciated.
I like to take advantage of CSS in situations like this.
absolutely position your div
use ng-style to bind top and left attributes to some in-scope variable
randomly change the top and left attributes of this in-scope variable
use CSS transitions on top and left attributes to animate it for you
I made a plnkr! Visit Kentucky!
Related
Here is a little jquery code, where any number of dots jump around. I want them to not collide on their path to the new coordinate. Is there a way to prevent them from colliding?
My thoughts where using the plugin collision, but I don't know how to use it on moving objects. The documentation also doesn't give a hint.
Here is the code https://jsfiddle.net/c0ffi124/anoxLdsb/16
function runGame(parameter) {
document.getElementById("blocks").style.display = "block";
document.getElementById('start-button').style.display = 'none';
let divs = document.getElementsByClassName("block");
for (div in divs) {
animateDiv(divs[div]);
}
};
function makeNewPosition() {
var height = $(window).height() - 50;
var width = $(window).width() - 50;
var newh = Math.floor(Math.random() * height);
var neww = Math.floor(Math.random() * width);
return [newh, neww];
}
function animateDiv(myclass) {
var newq = makeNewPosition();
$(myclass).animate({ top: newq[0], left: newq[1] }, 3000, function() {
animateDiv(myclass);
});
};
You can store the x and y coordinates of the dots.
You can check the distance between 2 dots with pythagorean theorem, and if it's too little, generate new x and y.
If sqrt(abs((x1-x2)*(x1-x2)) + abs((y1-y2)*(y1-y2))) > radius of one dot, the dots are collising.
So you can iterate over all of the possible point pairs, and do this checks.
So I want to add a class on a specific screen height. So I've done:
window.onscroll = function() {scrollPost()};
function scrollPost () {
var x = window.screen.width;
var i = window.scrollY;
var a = i / x;
animator (a);
slide(a);
}
function slide(x){
var a = (x * 100);
var i = Math.round(a);
console.log(i);
var slideIn = document.querySelector(".slide-in-right");
var slideOut = document.querySelector(".slide-out-left");
if (i >= 90){
slideOut.classList.add("animate");
slideIn.classList.add("animate");
slideIn.style.display = ("block");
}
The problem however. Is that on different screens, the value will be different. Thus therefore on different screens it will toggle at a different time. I could probably make ifstatements, based on screen width. But then I'd need a whole lot of them.
I want the animation to be added only after the container is 100% in the screen height. How would you do this?
You are going to have to get users viewport (window height).
Divide it by half
Add it towards your IF position.
I wrote a simular answer, how ever it was written jQuery, if you are considering it would be a better output.
How to trigger a class that is only in view with wapoints
However to implement that to plain js:
Get user screen height:
var w = window,
d = document,
e = d.documentElement,
g = d.getElementsByTagName('body')[0],
x = w.innerWidth || e.clientWidth || g.clientWidth,
y = w.innerHeight|| e.clientHeight|| g.clientHeight;
alert(x + ' × ' + y);
divide y by half, and then add to your current position that checks if element is scrolled.
I will add this just in case. To get element position.
function getPosition(element) {
var xPosition = 0;
var yPosition = 0;
while(element) {
xPosition += (element.offsetLeft - element.scrollLeft + element.clientLeft);
yPosition += (element.offsetTop - element.scrollTop + element.clientTop);
element = element.offsetParent;
}
return { x: xPosition, y: yPosition };
}
Source: How to get the distance from the top for an element?
Im still new to this type of programming, im trying to create kaledoscope kind of effect to be projected on screen. I want to make the image move isnide each section of the effect. is there a way to move it? i cant seem to target the canvas created by the plug in.
https://codepen.io/muspelheim/pen/gpymF
var images = [
"http://media-cache-ak0.pinimg.com/736x/5d/d8/41/5dd8416cbae27edeac61aa525a5df99d.jpg",
"https://1.bp.blogspot.com/-FpxaoVBBxXs/T5aWaP2dMDI/AAAAAAAAAw8/qdaPYyuqSt8/s1600/spugnaepicinfame.jpg",
"https://25.media.tumblr.com/tumblr_m9ls7nRTuR1rvqbato1_1280.jpg",
"https://3.bp.blogspot.com/-SJAKrZTcqwI/T5kwYk71YCI/AAAAAAAAAxE/HNlX3i2-xwk/s1600/spugnabimbofango.jpg"
];
// Let's create graphemescope object inside the container
var container = $("#container");
var scope = new Graphemescope( container[0] );
var index = 0;
function changePicture() {
scope.setImage(images[index]);
index = (index + 1) % images.length;
};
setInterval(changePicture, 2000);
changePicture();
$(window).mousemove(function(event) {
var factorx = event.pageX / $(window).width();
var factory = event.pageY / $(window).height()
// This will move kaleidoscope
scope.angleTarget = factorx;
scope.zoomTarget = 1.0 + 0.5 * factory;
});
var resizeHandler = function() {
container.height( $(window).height() );
container.width( $(window).width() );
};
$(window).resize(resizeHandler);
$(window).resize();
container.click(changePicture);
I'm trying to build an animated graph with paper.js that can react to different input. So I want to smoothly animate one point vertically to a different point.
I've looked at different examples and the closest ones to mine is this one:
paper.tool.onMouseDown = function(event) {
x = event.event.offsetX;
y = event.event.offsetY;
paper.view.attach('frame', moveSeg);
}
var x;
var y;
function moveSeg(event) {
event.count = 1;
if(event.count <= 100) {
myPath.firstSegment.point._x += (x / 100);
myPath.firstSegment.point._y += (y / 100);
for (var i = 0; i < points - 1; i++) {
var segment = myPath.segments[i];
var nextSegment = segment.next;
var vector = new paper.Point(segment.point.x - nextSegment.point.x,segment.point.y - nextSegment.point.y);
vector.length = length;
nextSegment.point = new paper.Point(segment.point.x - vector.x,segment.point.y - vector.y);
}
myPath.smooth();
}
}
This Code animates one Point to the click position, but I couldn't change it to my needs.
What I need is:
var aim = [120, 100];
var target = aim;
// how many frames does it take to reach a target
var steps = 200;
// Segment I want to move
myPath.segments[3].point.x
And then I dont know how to write the loop that will produce a smooth animation.
example of the graph:
I worked out the answer. The following steps in paperscript:
Generate Path
Set aim for the point
OnFrame Event that does the moving (eased)
for further animations just change the currentAim variable.
var myPath = new Path({
segments: [[0,100],[50,100],[100,100]]});
// styling
myPath.strokeColor = '#c4c4c4'; // red
myPath.strokeWidth = 8;
myPath.strokeJoin = 'round';
myPath.smooth();
// where the middle dot should go
var currentAim = [100,100];
// Speed
var steps = 10;
//Animation
function onFrame(event) {
dX1 = (currentAim[0] - myPath.segments[1].point.x )/steps;
dY1 = (currentAim[1] - myPath.segments[1].point.y )/steps;
myPath.segments[1].point.x += dX1;
myPath.segments[1].point.y += dY1;
}
Please, play with teh fiddle below. ONE bug goes as it should - turns its "head" and crawls in proper direction. But several bugs (starting with two and up) destroy it all. Jquery "each" returns coordinates twice so instead of two sets of coordinates for two bugs FOUR are generated.
$(document).ready(function () {
function bug() {
$('.bug').each(function () {
//var bugs = $('.bug').length;
var h = $(window).height() / 2;
var w = $(window).width() / 2;
var nh = Math.floor(Math.random() * h);
var nw = Math.floor(Math.random() * w);
//$this = $(this);
//var newCoordinates = makeNewPosition();
var p = $(this).offset();
var OldY = p.top;
var NewY = nh;
var OldX = p.left;
var NewX = nw;
var y = OldY - NewY;
var x = OldX - NewX;
angle = Math.atan2(y, x);
angle *= 180 / Math.PI
angle = Math.ceil(angle);
console.log(p);
$(this).delay(1000).rotate({
animateTo: angle
});
$(this).animate({
top: nh,
left: nw
}, 5000, "linear", function () {
bug();
});
});
};
bug();
});
http://jsfiddle.net/p400uhy2/
http://jsfiddle.net/p400uhy2/4/
As mentioned by #Noah B, the problem is that each "bug" is setting the loop for all "bugs".
I'd make bug() function per element, so that each "bug" can be set individually.
EDIT (#Roko C. Buljan comment)
function bug() {
// ... your code ...
// calculate animation time, so that each of bugs runs same fast in long and short distance:
var top_diff = Math.abs(OldY - nh),
left_diff = Math.abs(OldX - nw),
speed = Math.floor(Math.sqrt((top_diff * top_diff) + (left_diff * left_diff))) * 15;
$(this).animate({
top: nh,
left: nw
}, speed, "linear", function () {
// rerun bug() function only for that single element:
bug.call(this);
});
};
$('.bug').each(bug);
DEMO
The problem is that you had .each() calling a function with .each() in it...so each bug had the bug() callback. You just have to move the bug() call outside of the .each(){}. See fiddle: http://jsfiddle.net/p400uhy2/2/