The goal
I want to create a function which have couples of parameters like that:
MyObject.calculateResponsiveHeights({
containers: {
".content",
".sidebar"
},
spacing: {
125, // This will be attributed to ".content"
240 // This will be attributed to ".sidebar"
}
});
The problem
I do not how I can do this.
What I have now (the function implementation — just to be aware of the situation)
function calculateResponsiveMeasures() {
var containerContentResponsiveHeight = $(window).height() - 185,
sidebarProductsSummaryResponsiveHeight = $(window).height() - 255;
containerContentResponsiveHeight = containerContentResponsiveHeight + "px";
sidebarProductsSummaryResponsiveHeight = sidebarProductsSummaryResponsiveHeight + "px";
$(".container-content").css("height", containerContentResponsiveHeight);
$(".products-summary").css("height", sidebarProductsSummaryResponsiveHeight);
}
Yeah, that's disgusting, huh?
Observations
I'm not asking to improve my code, nor say whether it is better or worse way to do — I just want to better organize my function.
Cheers!
You're trying to create an array: [1, 2, 3].
However, you should use a single object instead:
{
".content": 125,
".sidebar": 240
}
You can then iterate over the properties using a for in loop.
Related
So I'm writing a game on JS Canvas and I'm making my own GUI from scratch. To do so, I made a button object with fields x, y, width, height and intersects(click_event). For some reason, when I directly put this expression for x, it returns NaN even though the expression works everywhere else.
It's just a simple game on Canvas. I know I could probably use some dirty trick to work around it, but I want to keep my code clean. I just don't understand why this wouldn't work.
var button = {
height:80,
width:200,
x:canvas.width/2 - this.width/2, //this is the problem
y:200,
//other stuff
};
console.log(button.x); //this prints "NaN"
console.log(canvas.width/2 - button.width/2); //prints correct num
The canvas width is 1000, so 1000 / 2 - 200 / 2 should equal 400, which it does when called inside console.log.
But when I put it inside button.x it evaluates to NaN.
You can't access/reference a property within a object during initialization.
So this will never work:
var myObject = {
height: 2
doubleHeight: 2 * this.height
}
One solution would be to add the poperty after you have initialized the object. Your code would like this:
var button = {
height:80,
width:200,
y:200,
//other stuff
};
button.x = canvas.width/2 - button.width/2
Another solution would be to wrap inside function
function createButton(height, width, canvasWidth) {
return {
height: height,
width: width,
y: width,
x: canvasWidth/2 - width/2
}
}
It can be achieved by using constructor function
var button = new function() {
this.height=80;
this.width=200;
this.x = canvas.width/2 - this.width/2;
this.y=200;
}
When using Hamster.js we have to define the parameter array as
params = {"array":my_array}
my_array is formed by elements with many attributes and I need to change the attributes x and y.
In the function I pass to Hamster.js I defined:
function map_node_hamster() {
params.array.forEach(function (d) {
d.x = some_calculation_here;
d.y = other_calculation_here;
}
}
but after calling the hamster.run() function, the elements of my original array stay intact.
As I need performance, I thought Hamsters could just change the values that my array is pointing. I actually do not know much about Javascript and how it manages arrays.
I'm calling the run function like this:
console.log("Before hamster:");
console.log(network.nodes);
p = {'array': network.nodes, "w": w, "h":h};
hamsters.run(p, map_node_hamster, function(output){console.log(output); return output;}, hamsters.maxThreads, true);
console.log("After hamster:");
console.log(network.nodes);
And the elements of network.nodes are intact after hamsters.run().
How could I change elements of array inside run function? Or.. How would be the right way to do the changes?
As the vector nodes is large, copying, sorting, and things like this will decrease performance and maybe it will be worst than single thread/non-parallel version.
It seems like the answer is to create an index array and change nodes in the callback function (output).
Despite the behavior of my "d3 graphic representation of network" is really not what I expected... maybe the code is actually right in the sense of answering my question (how to change objects from array in parallel computing with Hamsters.js). That is:
p = {'array': network.indexes,
"nodes": network.nodes,
"w": w,
"h": h};
hamsters.run(p, map_node_hamster, function (output) {
output.forEach(function (d) {
network.nodes[d.i].x = d.xy[0];
network.nodes[d.i].y = d.xy[1];
});
return output;
}, cores, true);
And... changing the function to work like this:
function map_node_hamster() {
pfor (var i = 0; i < params.array.length; i++) {
var result;
var d = params.nodes[params.array[i]];
var d = params.nodes[params.array[i]];
result = {x: d.x calculation, y: d.y calculation};
rtn.data.push({"i": params.array[i], "xy": [result.x, result.y]});
}
}
So, I am just diving into simple web animations for a game, and I am looking for advice. Eventually, I'll get a good grip on beziers and arcs and learn how to animate along a path to get some nice Diablo III-esque curving numbers but, for now, I am just trying to get the fundamentals down.
First (real) attempt
The key code is pretty simple-
paper.text(170, 95, dmgValue).attr({fill:"white", "font-size":16}).animate({
transform:"t0,-50", "fill-opacity":0} ,500).node.setAttribute("class", "no-select");
A CSS styling prevents the text from being highlighted (thanks to a user here for the help). The main issue, is that the text is still there with no opacity- you can hover over it and see the text cursor. Although it works, it' kind of messy looking. Also, since there is no variable assigned, I don't think I can dispose of it with Element.remove();
Where I am at now
There were a lot of small revisions I made in-between saved versions that made the code to the bulkiness that it is now. I wanted the ability to limit the number of numbers flying around at once (for slower computers), so I put them into an array that can be looped endlessly and used, although that probably isn't needed and it wouldn't be a big deal to leave it out.
Also moved from using transform, to setting the y-coords, and placing the .hide() into a separate function for the callback (which, for some reason worked instead of placing it at the end of the animation).
This version appears to work at first, but the animations get interrupted when you click too many times and I'm not sure why. I am sure I can figure it out in the end with enough time, but I might be making this too complicated, anyway. The full code-
var paper = Raphael(0, 0, 350, 350);
paper.canvas.style.backgroundColor = "Black";
var dmgValues = [],
dmgValuesIndex = 0,
maxMsgs = 15,
dmgXMaxOffset = 25,
dmgYMaxOffset = 25,
dmgXRef = 170 - dmgXMaxOffset,
dmgYRef = 250 - dmgYMaxOffset,
dmgMaxDistance = 50;
for (i=0; i< maxMsgs; i++) {
dmgValues[i] = paper.text().attr({fill:"white", "font-size":16});
dmgValues[i].node.setAttribute("class", "no-select");
dmgValues[i].hide();
}
var toggle = paper.rect(150, 270, 50, 25).attr({fill:"green"});
toggle.click(function() { doHit(); });
function doHit() {
var dmgHit = Math.floor(Math.random() * 99) + 1,
xPos = Math.floor(Math.random() * dmgXMaxOffset) + 1,
yPos = Math.floor(Math.random() * dmgYMaxOffset) + 1;
dmgValues[dmgValuesIndex].show();
if (dmgValues[dmgValuesIndex].status() == 1) { dmgValues[dmgValuesIndex].stop(); }
dmgValues[dmgValuesIndex].attr({x:dmgXRef + xPos, y:dmgYRef + yPos, text:dmgHit,
"fill-opacity":1}).animate({y:dmgYRef - dmgMaxDistance, "fill-opacity":0}, 600,
"linear", function() { afterEffects(dmgValues[dmgValuesIndex]) });
}
function afterEffects (afterTarget) {
afterTarget.hide();
dmgValuesIndex++;
if (dmgValuesIndex >= maxMsgs) { dmgValuesIndex = 0; }
}
CSS:
.no-select {
-moz-user-select: none;
-webkit-user-select: none;
}
I think I figured it out!
http://jsfiddle.net/rLcwax9k/10/
One thing I noticed was that that the incrementer was in the callback function that occurred after the animation, so it wasn't really counting right. But, mainly, because the dmgValuesIndex was global, and was getting incremented on each click. So, by the time the animation was done, it was doing functions based on whatever the current count was at the end of the animation in the callback, which may not have been the right one. So, I just put a parameter on the function and used that as the reference throughout the call and passed it to the callback.
Heh, I am sort of beginning to see why a lot of languages need setter and getter methods on their objects. This should be a good lesson to noobs like me on operating with global variable scope and their possible side-effects.
However, before I accept an answer, I am still looking for any other methods that may be more efficient.
Main code-
function doHit(iter) {
this.iter = iter;
var dmgHit = Math.floor(Math.random() * 99) + 1,
xPos = Math.floor(Math.random() * dmgXMaxOffset) + 1,
yPos = Math.floor(Math.random() * dmgYMaxOffset) + 1;
dmgValues[iter].show();
if (dmgValues[iter].status() == 1) { dmgValues[iter].stop(); }
dmgValues[iter].attr({
x:dmgXRef + xPos,
y:dmgYRef + yPos,
text:dmgHit,
"fill-opacity":1
})
.animate({
y:(dmgYRef + yPos) - dmgMaxDistance,
"fill-opacity":0},
1000,
">",
function() {
dmgValues[iter].hide();
}
);
}
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;
}
});
Is this horribly inefficient or does it look ok??? How do I test resources used by it?
$.easing.def = "easeOutBack";
$(document).ready(function() {
var numResults = $("#scroll > div").size();
var scrollSize = numResults * 264;
var stopSize = ((numResults - 6) * 264) * -1;
$("#scroll").width(scrollSize);
$("#page-left").hide();
$("#page-right").click(function() {
var marginleft = parseInt(jQuery("#scroll").css("margin-left"));
if(marginleft > stopSize) {
$("#page-left").show();
$(this).hide();
$("#scroll").animate({"margin-left": "-=783px"}, 800, function() {
var marginleft = parseInt(jQuery("#scroll").css("margin-left"));
if(marginleft > stopSize) {
$("#page-right").show();
}
});
}
});
$("#page-left").click(function() {
var marginright = parseInt(jQuery("#scroll").css("margin-left"));
if(marginright < -10) {
$("#page-right").show();
$(this).hide();
$("#scroll").animate({"margin-left": "+=783px"}, 800, function() {
var marginright = parseInt(jQuery("#scroll").css("margin-left"));
if(marginright < -10) {
$("#page-left").show();
}
});
}
});
});
Chrome gives you the ability to take heap snapshots. DeveloperTools->Profiles->HeapSnapshots
You can take snapshot at various time intervals to compare memory usage.
Another option is paid one http://www.softwareverify.com/javascript/memory/feature.html
I don't see any reason why that would consume much in terms of resources. You're just animating things left and right, right? I guess some better coding practices that I'd point out would be to store things you use repeatedly like $("#scroll") in a variable so you don't search the DOM every time for the same thing, and also choosing one of jQuery or $ unless you need to do otherwise.
The real question I'd have is what exactly 783 represents. If it's because your screen is 800 pixels wide, then keep in mind that not everyone will see you page that way.
As for the profiling part, Rizwan's answer gets +1.