how to re-write this jquery array to javascript - javascript

I am trying to re-write this code in javascript only without the jquery part.
var imgs = $.makeArray($("#images img"));
imgs.reverse();
function crossfade() {
TweenMax.to(imgs[0], 1, { autoAlpha: 0, scale: 1 });
TweenMax.to(imgs[1], 1, { autoAlpha: 1, scale: 1.2 });
imgs.push(imgs.shift());
}
var cycle = setInterval(crossfade, 3000);
Most especially the below part.
var imgs = $.makeArray($("#images img"));
imgs.reverse();

Get the Images with document.querySelectorAll, then put them in an array (as #rojo said in his comment) and reverse the order of that array.
var images = document.querySelectorAll("#images img"), //get the images as nodelist
images = Array.from(images), //transform the nodelist to an array
images = images.reverse() //reverse the array
// proceed with images...

This might help you
Array.from(document.querySelectorAll('#images img')).reverse()

Related

Create dynamic CSS file with Javascript

I am currently working on a CMS project to create perspective objects using CSS transform properties (scale, rotate, translate...) in 3d: XYZ.
When an object is created it has these characteristics in its matrix3d(-16 values-) returned by window.getComputedStyle(element) -> style['transform']
The next step is to create animations: through a set of input[range], the user can modify these objects' characteristics and get their final state once the animation is finished.
It works very well. The question now is to create the complete dynamic CSS system, object by object.
I have its matrix1 (initial matrix3d) and its matrix2 (final matrix3d). By executing
#keyframes anim {
from { transform: matrix1 }
to { transform: matrix2; }
}
document.getElementById('object').style.animation = 'anim 2s linear';
it should work on its own... The prob is to create the CSS instruction. Using:
document.styleSheets[0].insertRule('
#keyframes anim {
from { transform: matrix1 }
to { transform: matrix2; }
}'
);
works well but once it's created in the main CSS file, if user modifies the matrix2 I can't rewrite the same instruction twice...
My idea is to create a CSS file for each objet on the server then import it with JS: if user is satisfied I keep it, and if not I remove it and create a new one with its new matrix2.
the advantage is that I can keep the word 'anim' without risking conflict between objects since each will call its own CSS (i.e 'object1.css').
Is this the best way to proceed or do you recommend another one?
Another question: despite my research I can't find what the 16 values of matrix3d correspond to. Translate XYZ is in [12], [13], [14] but I don't have them all. If you know a more explicit resource than https://developer.mozilla.org/fr/docs/Web/CSS/transform-function/matrix3d() it may help.
Finally found the solution... maybe not the best but it works.
We create the first matrix3D (object in its initial state):
getObjectValues('objID', 0); // 0 for matrix1
The function
function getObjectValues(div, n){ // 0 for matrix1, 1 for matrix2
let element = document.getElementById(div);
let myTransform = window.getComputedStyle(element,null)
let matrix = myTransform.getPropertyValue("-webkit-transform");
if (matrix === 'none' || typeof matrix === 'undefined') {
// native HTML objects (as divs) are not in a 3D dimension space
// if necessary we create its 3D environment
element.style.transform = 'translateZ(1px)';
getObjectValues(div, n); // then reload the function
}
else {
matrixObj[n] = matrix;
}
}
// Array matrixObj at this step:
[0] -> matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1)
After playing with the different input type="range" (for position, rotation, ... in XYZ dimension) we create the second matrix3D (final state) by clicking on the "TEST" button, which calls
getObjectValues('objID', 1); // 1 for matrix2
// Array matrixObj at this step:
[0] -> matrix3d(1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 1, 1)
[1] -> matrix3d(0.945519, 0, -0.325568, 0, 0, 1, 0, 0, 0.325568, 0, 0.945519, 0, 0, 0, -48, 1)
Now the trick: we create a pseudo CSS sheet called "anim-update"
includeCSS("anim-update");
let styleSheet = document.getElementById("anim-update");
// the function
function includeCSS(css) {
let head = document.getElementsByTagName('head')[0];
let sheet = document.createElement('style');
sheet.setAttribute('id',css);
sheet.setAttribute('rel', 'stylesheet');
sheet.setAttribute('type', 'text/css');
head.appendChild(sheet);
}
Once its done we play these 3 sequences:
let delay = 2; // duration
// 1. returns the object to its initial state
setTimeout(function(){
document.getElementById(div).style.transform = matrixObj[0];
},100);
// 2. play the scenario
setTimeout(function(){
styleSheet.innerHTML = '#keyframes anim {
from { transform: '+matrixObj[n][0]+' }
to { transform: '+matrixObj[n][1]+' }
}';
document.getElementById(div).style.animation = 'anim '+delay+'s linear';
},500);
// 3. removes the temporary CSS at the end of the animation
setTimeout(function(){
document.getElementById('anim-update').outerHTML = "";
delete document.getElementById('anim-update');
},500+2000); // +2 seconds -> delay*1000
In this way User can change the final state of the object as much as he wants until he gets the desired animation, which he checks by clicking on the "TEST" button. A "SAVE" button retrieves the data from matrixObj and saves the 2 matrix values. Then move to the next object.

snap.svg save element and paste it to another

I create some lines in my Paper:
var svg = Snap("#svg_container");
var linesContainer = {};
var line = svg.line( 0, 0, 200, 200).attr(...);
linesContainer[someID] = line;
then i clear the Snap / create a new. I want to have the stored object also in my new snap:
svg = Snap("#svg_container");
svg.clear();
//something like:
//svg.append(linesContainer[someID]);
is this possible?
Here script with using SnapSVG.
var linesContainer = []; // not {}
lineContainer[linesContainer.length] = svg.line( 0, 0, 200, 200).attr(...);
// or 2nd way .. u can definitely make objects with value x,y, attrs and store them, but it helps reducing a storage of using memory.
U can put line to svg like that.
svg = Snap("#svg_container");
svg.clear();
for(i=0;i<lineContainer.length;i++)
svg.add(lineContainer[i]);

Multiple shape fadout with Kinetic js produces a stack overflow

Hello Stackoverflow community
As I am trying to build a small game, i came to a problem.
Somehow, when i try to fade out multiple shapes, respectivly a group with the shapes in it, some of the shapes will not fade out or browser gets a stack overflow.
So as i tried out several hours to fix the problem i need your help.
Heres the link to a little fiddle i made: http://jsfiddle.net/hnBPT/
As you can see theres a function newFadeShapesOut() which needs the nodes that should be fade out and also the layer of the nodes.
It moves the nodes into a group and fades the group out. Somehow and sometimes, one or more shapes will not fade out or there occurs a fatal error.
Function for fadeout:
function newFadeShapesOut(shapes, layer, callback, speed){
if(typeof(speed) == 'undefined'){
speed = 1;
}
var g = new Kinetic.Group();
console.log(layer.getChildren().length);
console.log(shapes.length);
layer.add(g);
shapes.each(function(shape){
shape.moveTo(g);
});
console.log(layer.getChildren().length);
console.log(shapes.length);
var tween = new Kinetic.Tween({
node: g,
opacity: 0,
duration: speed,
onFinish: function(){
if(typeof(callback) != 'undefined'){
callback();
tween.destroy();
}
}
}).play();
}
PS: Google Chrome is recommend, firefox tends to crash.
Thank you for your help.
EDIT: Sorry i forgot about that, you can activate the script by clicking the red square.
There's some strange behaviour going on here. Look at my comments as I tried to rewrite your function:
function fadeShapesOut(layer, callback, speed) {
var children = layer.children;
//The layer here already shows some children have moved.
//2 children remain, 1 text and 1 rect.
console.log("LAYER");
console.log(layer);
//Again, children shows that there are only 2 children of layer at this point: Test 2 and Button Rect
console.log('CHILDREN');
console.log(children);
if(typeof(speed) == 'undefined'){
speed = 1;
}
var group = new Kinetic.Group();
layer.add(group);
children.each(function(child) {
console.log("CHILD");
console.log(child); //This spits out Test 1, Test 3 and the newly added Group. (Strange order???
child.moveTo(group);
});
//Since group is already added to the layer, you're all of layer's children to group, including group itself. Which is causing a never ending loop of references to group including itself - causing the stack overflow.
var tween = new Kinetic.Tween({
node: group,
opacity: 0,
duration: speed,
onFinish: function(){
if(typeof(callback) != 'undefined'){
callback();
tween.destroy();
}
}
}).play();
}
What's messing you up is that the group is being considered a child of layer (Even though it hasn't been added yet in the order of function calls, which is strange behaviour to me). So when you loop through the children of layer in the each function, you're trying to move group --> group which screws up the reference in a never ending loop.
I logged a bunch of things in my fiddle, so go ahead and take a look to see some of the strange behaviour I was talking about above.
Anyways, if your callback is going to destroy the layer, what is the point of moving everything to a new group in the function? That Group is messing your code up and I don't see the point of it if you're just going to destroy the layer.
Instead you can achieve the effect you want by just tweening the layer itself:
function fadeLayer(layer, callback, speed) {
var tween = new Kinetic.Tween({
node: layer,
opacity: 0,
duration: 2,
onFinish: function(){
layer.destroy();
tween.destroy();
}
}).play();
}
If you must stick with your original function format, then you can grab children by using names:
newsobj[n] = new Kinetic.Text({
nid: n,
x: 140,
y: ((n == 0) ? 294.5 : 304.5 ),
text: news[n],
fill: 'white',
fontFamily: 'Corbel W01 Regular',
fontSize: 11.26,
name: 'fadeThisAway'
});
button = new Kinetic.Rect({
x: 10,
y: 10,
width: 100,
height: 100,
fill: 'red',
name: 'fadeThisAway'
});
In my example, I used the name fadeThisAway. And then, using your old function:
function newFadeShapesOut(layer, callback, speed){
var shapes = layer.get('.fadeThisAway');
if(typeof(speed) == 'undefined'){
speed = 1;
}
var g = new Kinetic.Group();
console.log(layer.getChildren().length);
console.log(shapes.length);
layer.add(g);
shapes.each(function(shape){
shape.moveTo(g);
});
console.log(layer.getChildren().length);
console.log(shapes.length);
var tween = new Kinetic.Tween({
node: g,
opacity: 0,
duration: speed,
onFinish: function(){
if(typeof(callback) != 'undefined'){
callback();
tween.destroy();
}
}
}).play();
}
Instead of passing shapes through the function, just call
var shapes = layer.get('.fadeThisAway');
at the beginning of the function (you're passing layer through the function already anyways) to grab the children that are named fadeThisAway. (Note: This works because the group is not named fadeThisAway)
Working example and comments inside: JSFIDDLE
UPDATE
Okay so I made a basic example of the issue with layer.children
2nd JSFIDDLE
And it looks like that's just how the children of layer works. This proves that you definitely have to distinguish between shapes and group, because the group will always be considered a child of layer.
The naming method works to distinguish your shapes between layers by giving all shapes a common name that excludes groups.
After several attempts to bend projeqht's function to my way i finally did it!
Somehow, the collection shapes just updates itself when adding the group to the layer!
If i use an array instead, it works.
Hope it helps someone!
So here my solution which works like a charm.
function fadeShapesOut(shapes, callback, speed){
layer = shapes[0].getLayer();
if(typeof(speed) == 'undefined'){
speed = 1;
}
var g = new Kinetic.Group();
layer.add(g);
for(i in shapes){
shapes[i].moveTo(g);
}
var tween = new Kinetic.Tween({
node: g,
opacity: 0,
duration: speed,
onFinish: function(){
if(typeof(callback) != 'undefined'){
callback();
}
tween.destroy();
}
}).play();
}
If you have further questions, don't mind contacting me.

unable to applyMatrix in three.js

I am trying to run an animation from a JSON file. I am using a custom JSON loader, (i.e. not the one included with three.js).
So I have an object named frames, which contain many frames, all of them have shape information, and a simulation_matrix, which contains data required for animation in the form of a 4by4 transformation matrix(generated from a python script).
So I am using this code for animation ..
and this is a sample JSON script to load.
// This method is for adding static shapes
// This works perfectly fine ..
parent.add_shape = function(frame)
{
var material = new THREE.MeshLambertMaterial({
color: frame.shape.color,
wireframe: true,
wireframeLinewidth: 0.1,
opacity: 0.5
})
var geometry = new THREE.CylinderGeometry(frame.shape.radius,frame.shape.radius,frame.shape.height,50,50);
// mesh_dict dictionary maps a mesh(shape) to its frame
parent.mesh_dict[frame] = new THREE.Mesh(geometry,material);
var init_orientation = frame.simulation_matrix[0];
var orienter = new THREE.Matrix4();
orienter.elements = [];
//Since simulation_matrix is generated from python, it is a
// list of lists, We need to push it to the elemens of Matrix4 manually ..
for(var i in init_orientation)
{
for(var j in init_orientation[i])
{
orienter.elements.push(init_orientation[i][j]) ;
}
}
parent.mesh_dict[frame].applyMatrix(new THREE.Matrix4());
parent.mesh_dict[frame].applyMatrix(orienter);
parent.scene.add(parent.mesh_dict[frame]);
parent.renderer.render(parent.scene,parent.camera);
}
// This method basically takes the meshes defined in add_shape, and
// applies simulation matrix to it, and requests animation frame for
// animation.
parent.animate = function()
{
for(var frame in JSONObj.frames)
{
// defining simulation_matrix in a var.
var matrix = JSONObj.frames[frame].simulation_matrix[parent.animation_counter];
var animation_matrix = new THREE.Matrix4();
animation_matrix.elements = [];
// pushing it to a Matrix4
for(var i in matrix)
{
for(var j in matrix[i])
{
animation_matrix.elements.push(matrix[i][j]) ;
}
}
console.log(animation_matrix);
console.log(animation_matrix.elements);
// Making sure we are not applying matrix to the earlier transform
//mesh_dict is a dictionary of meshes, used in creating shapes,mapped to the
//frame which contains them
parent.mesh_dict[JSONObj.frames[frame]].applyMatrix(new THREE.Matrix4());
// now applying transform, after setting to identity matrix ...
parent.mesh_dict[JSONObj.frames[frame]].applyMatrix(animation_matrix);
}
console.log(parent.animation_counter);
//update timestep ...
parent.animation_counter++;
// This is to loop over again and again ...
// assuming 10 animations frames
if(parent.animation_counter == 10){ parent.animation_counter = 0; }
requestAnimationFrame(parent.animate);
}
The problem is that I am able to create the multiple shapes, but when I apply simulation matrix to them in the loop, only one of them is animating, that too in very unexpected manner.
Well I have figured out what was wrong. Somehow, all the dictionary parent.mesh_dict[] keys were mapped to a same single object, instead of all objects as required. Now I debugged it, and it is working like a charm. Also your point is valid #WestLangley, as I now use mesh.matrix.identity() to get things done. Thanks, I will close this question now.

Selecting a set of elements from a simple one-dimensional array, with the target element in the middle

With a lack of math neurons in my brain, i struggle a bit in finding my way around this.
I need to create a simple javascript function that will receive three parameters:
A one-dimensional, normal indexed Array with X elements (the values being unique IDs)
A target ID to select
An amount of elements to return
The third parameter would ask the function to return a set of elements, with the element having the target ID being either in the center of the result, or next to it.
The result of the function should be an array as well.
A few examples to make it a more visual explanation:
function([100,120,140,160,180,200], 120, 3)
// should return [100,120,140]
function([100,120,140,160,180,200], 160, 4)
// should return [140,160,180,200]
function([100,120,140,160,180,200], 180, 5)
// should return [140,160,180,200,100]
The case covered by the last example is what confuses me while writing the code, which i am currently attempting to, but i find myself writing strange conditions, numerous if-statements and code that generally seems like a work-around. Also the cases of parameter 3 being larger than the amount of elements in parameter 1 are a bit of an over-brainer for me.
I feel unsafe continuing with this code, because it feels buggy and simply not proper. Surely somebody with proper math skills could provide me with the theory i need to understand how to accomplish this in a more elegant fashion.
Theory or pseudo-code will suffice, but if someone has something like this ready at hand, please don't hesitate to share it.
Thank You!
(Here is what i have written so far - based on the prototype JS class implementation)
var CBasicMatrix=Class.create({
initialize: function(elementList){
this.elementList=elementList;
},
select: function(id, amount){
if(amount>this.elementList.length)
amount=this.elementList.length;
if(!this.elementList.length) return false;
var elementIndex=this.elementList.indexOf(id);
if(elementIndex==-1) return false;
var isRound=amount%2==0;
var amountHalf=isRound ? (amount/2) : (Math.ceil(amount/2)-1);
// [464,460,462,461,463]
var result=[];
if(elementIndex-amountHalf >= 0) {
var startIndex=(elementIndex-amountHalf);
for(i=startIndex;i<=startIndex+amount;i++){
result.push(this.elementList[i];
}
} else {
// more seemingly stupid iterative code coming here
}
}
});
Edit: In order to make this more understandable i will state the purpose. This code is supposed to be used for kind of a slideshow, in which multiple elements (parameter 3) are visible at the same time. Parameter 1 is the list of (the IDs of the) total elements in their correct order as they appear in the HTML declaration. Parameter 2 is the element that is currently selected and therefore should appear in the middle.
Here is my solution:
function method(arr, value, n) {
var result = [],
len = arr.length,
index = arr.indexOf(value);
for (var i = 0; index > -1 && i < n ; i++) {
result.push(arr[(len + index - ~~(n / 2) + (n % 2 ^ 1) + i) % len]);
}
return result;
}
TESTS:
var arr = [100, 120, 140, 160, 180, 200];
method(arr, 120, 3); // [100, 120, 140]
method(arr, 160, 4); // [140, 160, 180, 200]
method(arr, 180, 5); // [140, 160, 180, 200, 100]
method(arr, 100, 3); // [200, 100, 120]
I will help you by providing a pseudo code :
1 . if there is no match you should return an empty array.
2 . if there is a match you just divide the third parameter by 2, you take the result , you loop from the element found's index minus the previous result until the third parameter's value and you store the elements in a new array.
3 . you return the new array.
Update:
I saw your code and I don't see any problem with it.
After some careful debugging and overthinking my approach, i managed to find a solution that seems proper and safe. I am sure this could be optimised further and if anyone has any suggestions, feel free to share them.
var CBasicMatrix=Class.create({
initialize: function(elementList){
this.elementList=elementList;
},
select: function(id, amount){
if(amount>this.elementList.length)
amount=this.elementList.length;
if(!this.elementList.length) return false;
var elementIndex=this.elementList.indexOf(id);
if(elementIndex==-1) return false;
var isRound=amount%2==0;
var amountHalf=isRound ? (amount/2) : (Math.floor(amount/2));
var result=[];
var startIndex=(elementIndex-amountHalf);
var endIndex=(startIndex+amount-1);
var targetIndex=0;
for(i=startIndex;i<=endIndex;i++){
targetIndex=i;
if(i>this.elementList.length-1) targetIndex=i-this.elementList.length;
if(i<0) targetIndex=i+this.elementList.length;
result.push(this.elementList[targetIndex]);
}
return result;
}
});

Categories

Resources