How to Update CSS and Variable Using GSAP Tween - javascript

Consider the following code (not tested, just an example):
const item = document.getElementById('test');
let value = 0;
let finalValue = 100;
TweenMax.fromTo(
item,
.2,
{ '--some-var': value },
{
'--some-var': finalValue
onComplete: () => {
value = finalValue;
}
}
);
The above code uses TweenMax (although TweenLite would be preferred if it supports what I need...) to update the --some-var CSS property of item. At the moment, I am using onComplete to update value to the finalValue of the animation, however, I would ideally like to do this at the same time as the tween.
In other words, I would like the Tween to update the following two values as it runs:
--some-var of item
value
I am aware that I can pass an array to target, but from what I understand, that will set the value variable to an object like so { '--some-var': XXX } instead of just XXX.
Is there a way to update two objects that have different structures? i.e. One is a DOM node (CSS update), and one is a simple variable...

This is definitely possible. In fact, Carl made a quick tip on how to do so. Just make sure you are animating the actual variable, not the element where it is called.
If you want more help in your case, please provide a minimal example of the code that reproduces your error.

Related

ES6 calling method in another class, using modules

I know there is many questions like this asked, but I have been searching for hours and can't find any answers. I have this method, which takes in a parameter, which should be ID of two selects. Using this parameter, I want to determine which select is used and execute the if statement, but to no avail. When I run it, it shows no errors in console in Chrome and it does nothing. Can anyone shed some light on it, this is the method in one export class:
static styleCircle(select) {
if(this.select === ELEMENTS.ELEMENT_COLOR_SELECT) {
var getColor = ELEMENTS.ELEMENT_COLOR_SELECT;
var colorValue = getColor.options[getColor.selectedIndex].value;
ELEMENTS.ELEMENT_STYLE_CIRCLE.style.backgroundColor = colorValue;
} else if(select == ELEMENTS.ELEMENT_BORDER_SELECT) {
var getRadius = ELEMENTS.ELEMENT_BORDER_SELECT;
var radiusValue = getRadius.options[getRadius.selectedIndex].value;
ELEMENTS.ELEMENT_STYLE_CIRCLE.style.borderRadius = radiusValue;
}
}
This is it being called in another class, on two select elements, and the class is imported at the top of the file:
ELEMENTS.ELEMENT_COLOR_SELECT.onchange = Script.styleCircle(this);
ELEMENTS.ELEMENT_BORDER_SELECT.onchange = Script.styleCircle(this);
ELEMENTS is a file with constants, which are just being used to get ID's from the HTML file. I used other methods like this, with onclick events, but none had parameters, and now I'm stuck here. Thanks in advance.
You don't want to call the functions right now but instead you probably want to pass functions. Through that you can access the proper this and pass it to styleCircle:
ELEMENTS.ELEMENT_COLOR_SELECT.onchange = function() {
Script.styleCircle(this);
};
ELEMENTS.ELEMENT_BORDER_SELECT.onchange = function() {
Script.styleCircle(this);
};
Additionally this.select is probably causing you troubles as window.select is undefined.
First step would be to try debugging and ensure select is equivalent to either of those constants. Make sure you have full branching coverage in your debugging. That would mean start by adding an else statement to that if/else if statement - it's possible that your select is not equal to either constant and so neither branch is run.

For each value in the array change to the same image in CSS

There is an array which will increase and decrease in size and I was trying to implement something that will allow the code to go through each value in the array and perform the following code: (set the same image for each value)
if (something) {
myArray[0].css("background-image", "url(pictures/img.png)")
myArray[1].css("background-image", "url(pictures/img.png)")
}
The code above works however, it only works for the first two values, what if there is more? or less?
I was thinking of implementing forEach method so it could actually replace the image within every value, however it is not a variable as it modifies the CSS file and I am slightly confused how I could do that since I couldn't find relevant example, so here's the code I thought it might work but it doesn't
if (something) {
myArray.forEach(value) {
myArray.css("background-image", "url(pictures/img.png)")
}
}
Also, it's all inside a function and jQuery has been specified already, that's why you see me using .css without $ sign
Any help appreciated
This loops through your array and updates each of the jQuery elements.
if (something) {
for (var i = 0; i < myArray.length; i++) {
myArray[i].css("background-image", "url(pictures/img.png)");
}
}

Javascript - Array of prototype functions

I'm a javascript newbie so I'm writing ugly code so far sometimes due to my lack of experience and how different it is to the languages I'm used to, so the code I'll post below works, but I'm wondering if I'm doing it the right way or perhaps it works but it's a horrible practice or there is a better way.
Basically, I have a little dude that moves within a grid, he receives from the server an action, he can move in 8 directions (int): 0:up, 1: up-right, 2: right... 7: up-left.
the server will send him this 0 <= action <= 7 value, and he has to take the correct action... now, instead of using a switch-case structure. I created a function goUp(), goLeft(), etc, and loaded them in an array, so I have a method like this:
var getActionFunction = actions[action];
actionFunction();
However, what to set all this up is this:
1) create a constructor function:
function LittleDude(container) {
this.element = container; //I will move a div around, i just save it in field here.
}
LittleDude.prototype.goUp() {
//do go up
this.element.animate(etc...);
}
LittleDude.prototype.actions = [LittleDude.prototype.goUp, LittleDude.prototype.goUpLeft, ...];
//In this array I can't use "this.goUp", because this points to the window object, as expected
LittleDude.prototype.doAction = function(action) {
var actionFunction = this.actions[action];
actionFunction(); //LOOK AT THIS LINE
}
Now if you pay attention, the last line won't work.. because: when i use the index to access the array, it returns a LittleDude.prototype.goUp for instance... so the "this" keyword is undefined..
goUp has a statement "this.element"... but "this" is not defined, so I have to write it like this:
actionFunction.call(this);
so my doAction will look like this:
LittleDude.prototype.doAction = function(action) {
var actionFunction = this.actions[action];
actionFunction.call(this); //NOW IT WORKS
}
I need to know if this is hackish or if I'm violating some sort of "DO NOT DO THIS" rule. or perhaps it can be written in a better way. Since it seems to me kind of weird to add it to the prototype but then treating it like a function that stands on its own.
What you are trying to do is one of the possible ways, but it is possible to make it more simple. Since object property names are not necessary strings, you can use action index directly on prototype. You even don't need doAction function.
LittleDude = function LittleDude(container) {
this.container = container;
}
LittleDude.prototype[0] = LittleDude.prototype.goUp = function goUp() {
console.log('goUp', this.container);
}
LittleDude.prototype[1] = LittleDude.prototype.goUpRight = function goUpRight() {
console.log('goUpRight', this.container);
}
var littleDude = new LittleDude(123),
action = 1;
littleDude[action](); // --> goUpRight 123
littleDude.goUp(); // --> goUp 123
actionFunction.call(this); //NOW IT WORKS
I need to know if this is hackish or if I'm violating some sort of "DO NOT DO THIS" rule. or perhaps it can be written in a better way.
No, using .call() is perfectly fine for binding the this keyword - that's what it's made for.
Since it seems to me kind of weird to add it to the prototype but then treating it like a function that stands on its own.
You don't have to define them on the prototype if you don't use them directly :-) Yet, if you do you might not store the functions themselves in the array, but the method names and then call them with bracket notation:
// or make that a local variable somewhere?
LittleDude.prototype.actions = ["goUp", "goUpLeft", …];
LittleDude.prototype.doAction = function(action) {
var methodName = this.actions[action];
this[methodName](); // calls the function in expected context as well
}

Changewheel functionality How it works?

First of all I want share my appreciation for the amazing work done with this snippet (it's really really a cool tool).
I am trying to use mobiscroll in an app that I am currently developing. I love how easy is to use and customize the mobiscroll tool.
What I really find just obscure, is how use the functionality changeWheel. I tried many things but never with success.
What I am trying to accomplish is to change the values of the first wheel (change completely and regenerate the first wheel), when in my second wheel I select (actually what I want is an on change event) one of the two parameters present.
I build up a function that create the arrays for the two wheels, and that change array of the first wheel relatively to the index of the second wheel returned. (I can see that the function works, and that it generate the exact values for the wheels).
How then I can implement this with the onchange event on the inst, using the function changewheel???
Is this function changewheel suppose to do what I am looking for?
To be very clear, think as an example:
first wheel weight of a person
second wheel unit of measurement (kg or Lbs)
If I change on the spot Lbs to Kg, I want that the first wheel reflect the changes (updating the values available) - if for example i set the limit weight between 0 and 80kg the correspondent value in lbs need to be between 0 and 177lbs (the whole conversion is handled separately with another customized function, and it works exactly as I want).
I can't figure out how instead implement the changewheel event....an example or some more deep explanation will be really useful.
Thank you so much
Best
Dinuz
here goes a simple explanation, if you want to update the values of a diferent whell you need to pass the instance of the mobiscroll and call the method options
$(function(){
var filtersMetrics = [{}];
var wheelPosMetrics = []
var wheelPosFunc1 = [];
var wheelPosFunc = [];
wheelPosMetrics[0] = "Connection";
wheelPosMetrics[1] = "Shared";
wheelPosMetrics[2] = "Deleted";
filtersMetrics[0]['Metrics']=wheelPosMetrics;
wheelPosFunc1[0] = "Count";
wheelPosFunc[0] = "Count";
wheelPosFunc[1] = "Sum";
wheelPosFunc[2] = "Avg";
filtersMetrics[0]['Func']=wheelPosFunc1;
var metricsScroller = $("#select").mobiscroll().scroller({
theme : 'android',
display : 'inline',
mode: 'scroller',
wheels: filtersMetrics,
rows: 3,
'onChange' : function(v, i , e){
if(v[0]==1){
filtersMetrics[0]['Func']=wheelPosFunc;
metricsScroller.mobiscroll('option', 'wheels', filtersMetrics);
}else{
filtersMetrics[0]['Func']=wheelPosFunc1;
metricsScroller.mobiscroll('option', 'wheels', filtersMetrics);
}
}
});
});
I have used the 2.5 version
I also wasn't able to get changeWheel to work, but I found a workaround (I'm using Mobiscroll v2.15.1).
In the onChange–Handler you can set the default values dynamicaly:
.
.
.
onChange: function (values) {
// here your logic for the current values
if (/*here your condition*/) {
// Example for three wheels:
var curWheel = ["1", "2", "3"];
// set the default values
$(/*your element*/).mobiscroll("setArrayVal", curWheel, true);
}
},
.
.
.

Optimizing Javascript Loop for Wheel Game

I have a game I'm creating where lights run around the outside of a circle, and you must try and stop the light on the same spot three times in a row. Currently, I'm using the following code to loop through the lights and turn them "on" and "off":
var num_lights = 20;
var loop_speed = 55;
var light_index = 0;
var prevent_stop = false; //If true, prevents user from stopping light
var loop = setTimeout(startLoop, loop_speed);
function startLoop() {
prevent_stop = false;
$(".light:eq(" + light_index + ")").css("background-color", "#fff");
light_index++;
if(light_index >= num_lights) {
light_index = 0;
}
$(".light:eq(" + light_index + ")").css("background-color", "red");
loop = setTimeout(startLoop, loop_speed);
}
function stopLoop() {
clearTimeout(loop);
}
For the most part, the code seems to run pretty well, but if I have a video running simultaneously in another tab, the turning on and off of the lights seems to chug a bit. Any input on how I could possibly speed this up would be great.
For an example of the code from above, check out this page: http://ericditmer.com/wheel
When optimizing the thing to look at first is not doing twice anything you only need to do once. Looking up an element from the DOM can be expensive and you definitely know which elements you want, so why not pre-fetch all of them and void doing that multiple times?
What I mean is that you should
var lights = $('.light');
So that you can later just say
lights.eq(light_index).css("background-color", "red");
Just be sure to do the first thing in a place which keeps lights in scope for the second.
EDIT: Updated per comment.
I would make a global array of your selector references, so they selector doesn't have to be executed every time the function is called. I would also consider swapping class names, rather than attributes.
Here's some information of jQuery performance:
http://www.componenthouse.com/article-19
EDIT: that article id quite old though and jQuery has evolved a lot since. This is more recent: http://blog.dynatrace.com/2009/11/09/101-on-jquery-selector-performance/
You could try storing the light elements in an array instead of using a selector each time. Class selectors can be a little slow.
var elements = $('.light');
function startLoop() {
prevent_stop = false;
$(elements[light_index]).css('background-color', '#fff');
...
}
This assumes that the elements are already in their intended order in the DOM.
One thing I will note is that you have used a setTimeout() and really just engineered it to behave like setInterval().
Try using setInterval() instead. I'm no js engine guru but I would like to think the constant reuse of setTimeout has to have some effect on performance that would not be present using setInterval() (which you only need to set once).
Edit:
Curtousy of Diodeus, a related post to back my statement:
Related Stack Question - setTimeout() vs setInterval()
OK, this includes some "best practice" improvements, if it really optimizes the execution speed should be tested. At least you can proclaim you're now coding ninja style lol
// create a helper function that lend the array reverse function to reverse the
// order of a jquery sets. It's an object by default, not an array, so using it
// directly would fail
$.fn.reverse = Array.prototype.reverse;
var loop,
loop_speed = 55,
prevent_stop = false,
// prefetch a jquery set of all lights and reverses it to keep the right
// order when iterating backwards (small performance optimization)
lights = $('.light').reverse();
// this named function executes as soon as it's initialized
// I wrapped everything into a second function, so the variable prevent_stop is
// only set once at the beginning of the loop
(function startLoop() {
// keep variables always in the scope they are needed
// changed the iteration to count down, because checking for 0 is faster.
var num_lights = light_index = lights.length - 1;
prevent_stop = false;
// This is an auto-executing, self-referencing function
// which avoids the 55ms delay when starting the loop
loop = setInterval((function() {
// work with css-class changing rather than css manipulation
lights.eq( light_index ).removeClass('active');
// if not 0 iterate else set to num_lights
light_index = (light_index)? --light_index:num_lights;
lights.eq( light_index ).addClass('active');
// returns a referenze to this function so it can be executed by setInterval()
return arguments.callee;
})(), loop_speed);
})();
function stopLoop() {
clearInterval(loop);
}
Cheers neutronenstern

Categories

Resources