Push and Unshift Operation in javascript object - javascript

I have the following dataset
Input:
dataset[0]=[{data:29, color:"y"},{data:44, color:"g"}]
dataset[1]=[{data:16, color:"r"},{data:23, color:"m"},{data:23, color:"b"}]
I am showing this information on bar chart, however bar chart attempting to group them. And it does not give me what I expect. http://jsfiddle.net/7dhb4jh0/1
Therefore,I need to have the following output before I feed my bar chart
The logic behind the desired output to match the length of two dataset by adding {data:0, color:null} There are two things involved unshift and push operations
Desired Output:
dataset[0]=[{data:29, color:"y"},{data:44, color:"g"},{data:0, color:null},{data:0, color:null},{data:0, color:null}]
dataset[1]=[{data:0, color:null},{data:0, color:null},{data:16, color:"r"},{data:23, color:"m"},{data:23, color:"b"}]
Initial Attempt
I have did it as follows, https://jsfiddle.net/s8mywm33/1/
dataset=[];
dataset[0]=[{data:29, color:"y"},{data:44, color:"g"}]
dataset[1]=[{data:16, color:"r"},{data:23, color:"m"},{data:23, color:"b"}]
sum1=dataset[0].length
sum2=dataset[1].length
for(i=0;i<sum1;i++)
{
dataset[1].unshift({data:0, color:null})
}
for(i=0;i<sum2;i++)
{
dataset[0].splice(2, 0, {data:0, color:null});
}
console.log(dataset[0]);
console.log(dataset[1]);
However is there a better way to do it?

As per my recommendations in the comments, there are a number of ways you could be doing this. The one I'd recommend is just using a dummy value (as I mentioned here):
var blank = {data:0, color:null};
var dataset = [];
dataset[0] = [{data:29, color:"y"}, {data:44, color:"g"}, blank, blank, blank];
dataset[1] = [blank, blank, {data:16, color:"r"}, {data:23, color:"m"}, {data:23, color:"b"}];
This makes your intentions visibly clear for what data should be where, and doesn't require that much extra code.

Related

How would I hypothetically give submittable text an integer value in one js file and visualize it on an analytics page on another js file?

I've been having trouble for days trying to figure this out. I am able to transfer some basic methods like alert() and console.log() using function include(file) and I am able to display plain integers assigned to variables on a **bar graph in a browser, but I can't seem to do anything more complex. I tried assigning integers along with strings to a *variable, but the bar graph don't show up. Can anybody give me any pointers on how I could do this?
What I am trying to do is display on a graph how many bugs users have reported through bug tracking webpage.
*An example of what I tried:
var issue = {
id: issueId,
description: issueDesc,
severity: issueSeverity,
assignedTo: issueAssignedTo,
status: issueStatus
} && +1
**The code I used for the bar graph
var intVal = 5
var numArr = function(){
return Array.from({length: 2}, () => intVal);
}

Individual custom start position in Qualtrics through Javascript

I want to use either a slider question or a draggable bar chart in Qualtrics to present to respondents how they answered in former questions. More specifically, I compute a value out of then answers with weighting, and want the slider or bar to be positioned at this value.
Notably, as each respondent has a value (stored in an embedded data field), the position will thereby be individual for each respondent. Piping only works for text fields, as far as I understood the support page.
Based on this question/answer I came to the following code for the bar graph:
Qualtrics.SurveyEngine.addOnload(function()
{
var result = "${q://Field/result}";
var qwidth = $('QID1936~1~track').offsetWidth;
var resrec = ((qwidth*result)/100);
$('QID1936').select('.bar').each(function(name, index) {
name.setStyle({ width: resrec +"px"});
});
});
Basically, I get the result for each respondent out of the embedded data, get the width of the full bar graph, compute the ratio that should be colored based on the result, and update the position of the bar graph (following the mentioned answer).
Funny enough, everything works when done in the console. Also, the embedded data is correctly loaded, qwidth as well.
Two problems arise: it seems resrec could be computed wrongly, as a console.log() spits out 0 instead of the correct value. I assumed this could be somehow as a variable is not recognized as number, but several tries with Number() or 0+var did not change how this works in Qualtrics. In the console, it works just fine.
Also, no update of the bar (or slider with similar code) happens, neither with the correct value nor with the 0 that is produced by Qualtrics.
I search for two things: either a solution to the Javascript problem as described, basically how I can update the bar or slider with embedded data. Or another solution how to directly get embedded data into one of those two question formats as a starting value for each respondent individually.
Thanks for your help or ideas!
Try this:
Qualtrics.SurveyEngine.addOnload(function()
{
var qid = this.questionId;
var result = parseFloat("${e://Field/result}");
var qwidth = $(qid+'~1~track').offsetWidth;
var resrec = ((qwidth*result)/100);
$(qid).select('.bar').each(function(name, index) {
name.style.width = resrec + "px";
});
});
Notes:
It is best not to use a hardcoded QID
In a pipe use e: to refer to an embedded variable. q: is for questions.
Use parseFloat to convert the string to a number
No need to use setStyle if you are only setting one value
One solution proposed by Qualtrics support: when you use bars and/or sliders, piped values are actually possible.
The trick is to have the value of the bar/slider shown (a thing we do not use in the whole survey elsewhere). Then, you can access over the Advanced Question Options > Add Default Choices the blue arrow for piping text behind the value. Through this, the value is individually set to either embedded data or another answer.
Note, however, to tick "Show value" before accessing the default choices, else you will only be able to drag around the bar and set it for all simultaneously.
Here is a solution using the Qualtrics Question API method setChoiceValue that does not require you to compute the ratio and update the length of the bars manually.
Below is an example code for the result of ten respondents saved in embedded data from previous questions.
Qualtrics.SurveyEngine.addOnload(function()
{
var embedded = ["${e://Field/r1}", "${e://Field/r2}",
"${e://Field/r3}", "${e://Field/r4}", "${e://Field/r5}",
"${e://Field/r6}", "${e://Field/r7}", "${e://Field/r8}",
"${e://Field/r9}", "${e://Field/r10}"];
for (var i = 0; i < 11; i++) {
var index = i + 1;
var choiceInput = embedded[i];
this.setChoiceValue(index, choiceInput);
}
});
For one respondent:
Qualtrics.SurveyEngine.addOnload(function()
{
var value = "${e://Field/r1}";
this.setChoiceValue(1, value);
});

onkeydown, and auto complete

I was wondering if anyone could help me solve this issue or point me towards the right direction.
In my project we have a filed that needs to be autofilled, at this moment I use onblur which works wonders as it only does it so once you leave the focus. However, due to recent changes, it needs to only do so when there is only one unique item in the map which it matches the input.
I have a large array defined as following:
var myArray = [
[content, content],
[content, content],
...
]
Later in my code I associate it with a map, at least this is what most stackoverflow questions I looked at referred to it as follows:
var myMap = {};
for(0 to myArray.length) {
var a = myArray[i][0];
var b = myArray[i][1];
myMap[a] = b;
}
Now, finally I iterate over this array as follows:
for (var key in map) {
if (map.hasOwnProperty(key)) {
if (map[key].toLowerCase().indexOf(location.toLowerCase()) >= 0)
the above is the line of code I am struggling to figure out how to change. At this moment, while using on blur, if I type in the letter 'A' for example, and leave the focus area it will automatically fill it in with a certain name. However, in the array there are many other objects that begin with, or contain A. How can I change it so that the onkeydown event will keep going until it finally filters it down to to only possible key-value pair? I tried looking at MDN's documentation for filtering, but I do not think that will work for my purposes, or at least I am too inexperienced with JS.
If the indexOf the first and last are nonnegative and equal, there is just one. You could do this with an && and boolean short circuit evaluation, but that will run very far right off the screen, so I am showing your code with one more nested if (up to you to add the end of the block). But we also need to see if there are matches on multiple keys.
var matchCount=0;
for (var key in map) {
if (map.hasOwnProperty(key)) {
if (map[key].toLowerCase().indexOf(location.toLowerCase()) >= 0){
if (map[key].toLowerCase().indexOf(location.toLowerCase()) == map[key].toLowerCase().lastIndexOf(location.toLowerCase())) {
matchCount++;
then outside your for loop:
if (matchCount==1){ //do your stuff

Flash/Animate CC Tween Formatted Number

I'm using Animate CC (the erstwhile Flash CC) to do some ads that I'm exporting in HTML5 format (<canvas> and CreateJS stuff). They're working quite nicely overall.
I have a formatted number, in a Static Text box, like so: 5,000,000 and I want to tween it to, say, 20,000, over the course of 30 frames. I want to tween the same text to 5,000 and 1,000,000 and so on throughout the course of my scene.
In my limited Animate CC experience, I've managed to avoid using any Javascript, but I imagine that I will need to now. So, my question: how do I do this?
My thoughts on ways of doing this:
Since I'm using CreateJS, which has the TweenJS library as part of it, maybe I can just use that for tweening? Make little Actions at different points of my timeline? Not sure how all that works, and a lot of the references online are for ActionScript 3 or even AS2. Sample code would be appreciated.
If I do get into Javascript, there's the question of how I would do the number formatting. I could tween the number as 5000000 -> 20000 and on each frame update insert commas, that's one way of doing it. But to make matters more complex, these ads are going to be translated, and different locales come into the mix. So in English you get 5,000,000 and in German would you have 5.000.000, of course.
Since we're talking Javascript in the browser, I'm aware of the method Number.prototype.toLocaleString() which does the following:
The toLocaleString() method returns a string with a language sensitive
representation of this number.
That seems like it would do the trick, but then I have to worry about browser compatibility and what happens if I don't specify a locale. Ideally, since the German ads would only be displayed to people who had a German locale on their browser/OS, I could just call the method without any locale specified, and it would read it off the user's computer. I suppose it's possible to have the scenario where a German person is seeing an English ad, but I'm not that worried about it.
However, on the MDN page for toLocaleString() it has this big warning about earlier versions of FF defaulting to Western Arabic digits, so it makes me doubt the use of the method entirely.
Finally, I have the interesting fact that the translators will almost certainly take 5,000,000 and convert it into 5.000.000 for German. So it may be possible to avoid the use of toLocaleString() since I'll already have localized text. So if it were possible to write a simple Javascript function that could tween arbitrarily formatted numbers, I think that would do the trick. Perhaps:
Take the starting number and rip formatting out of it, save it
Tween the number
On each frame update, inject the formatting back into it
Probably not that hard from a JS perspective, but where I get stumped is how the heck I would do this in Animate/Flash and/or with CreateJS/TweenJS?
As far as tweening a formatted number using TweenJS, you can just tween a non-formatted number, and on "change", create a formatted version to do what you need:
createjs.Tween.get(obj, {loop:true})
.to({val:10000}, 4000)
.to({val:0}, 4000)
.on("change", formatNumber);
function formatNumber(event) {
// Round and format
var formattedNumber = (obj.val|0).toLocaleString();
}
Here is a simple fiddle: http://jsfiddle.net/m3req5g5/
Although Lanny gave some good data, I wanted to lay out exactly what I ended up doing to get this working.
First, you need to get a reference to the object you're going to be tweening in some way. When you make an Action in Flash and write Javascript, this is bound to the Stage, or to the MovieClip or Graphic that you're editing:
http://createjs.com/html5ads/#Scope
You can access objects using their instance names which are defined in Flash on the Properties of the object, once you've placed it on the Stage. Some sources online said that it was based on the symbol name or some such, but I haven't found that to be the case.
// Get a reference to the object you want to tween
var obj = this.anInstanceName;
Note that, if you want to access something that's inside a MovieClip, you will need to give your MovieClip on the stage an instance name, and then go inside the MovieClip and give an instance name to your target object. Then you can just walk down the hierarchy:
// Get a reference to the nested object you want to tween.
var obj = this.movieClipInstanceName.nestedInstanceName;
Now you can tween any numeric property of the object in question. For me, because I wanted to tween the text, I set an additional property on the object and tweened that, then formatted and copied it over into the text property as I went along.
It was useful to be able to specify how many frames the tween lasted, rather than the milliseconds, so I passed the useTicks flag.
obj.counter = 0;
createjs.Tween.get(obj, {useTicks: true})
.to({counter: 100}, 30) // <- 30 frames, this number is ms without useTicks
.on("change", formatNumber);
function formatNumber(event) {
obj.text = obj.counter.toLocaleString();
}
The above is generally applicable. Otherwise, here's the working code that I ended up using. It should be able to be dropped into a Flash Action in an HTML5 Canvas project and just work.
// Figures for tweening
var textStart = "2,000";
var textEnd = "6,000,000";
// Locate our target text box
var target = this.myTextBox; // replace "myTextBox" with your instance name
// Get our formatting data and so on
var data = this.getFormatData(textStart);
// Set up the text box
target.number = data.number;
target.text = textStart;
// Get the raw number we're tweening to
var endNumber = this.getFormatData(textEnd).number;
// Create the tween
createjs.Tween.get(target, {useTicks: true})
.to({number:endNumber}, 30)
.on("change", format);
//Formatting function, gets called repeatedly for each frame
function format(event) {
var rounded = Math.round(target.number);
var formatted = formatNumber(rounded, data.format);
target.text = formatted;
}
// UTILITY FUNCTIONS:
// Takes "###,###,###" or somesuch
// Returns a raw number and a formatting object
function getFormatData(formattedNumber) {
var toString = "" + formattedNumber; // in case it's not a string
var reversed = toString.split('').reverse(); // get a reversed array
// now walk (backwards) through the array and remove formatting
var formatChars = {};
for (var i = reversed.length-1; i >= 0; i--) {
var c = reversed[i];
var isnum = /^\d$/.test(c);
if (!isnum) {
formatChars[i] = c;
reversed.splice(i, 1);
}
}
// get the actual number
var number = parseInt(reversed.reverse().join(''));
// return the data
var result = {number: number, format: formatChars};
return result;
}
// Takes a raw number and a formatting object and produces a formatted number
formatNumber(number, format) {
var toString = '' + number;
var reversed = toString.split('').reverse();
var index = 0;
while (index < reversed.length) {
if (format[index]) {
reversed.splice(index, 0, format[index]);
}
index++;
}
var finished = reversed.reverse().join('');
return finished;
}
This fiddle demos the formatting and has a bit more of an explanation in the comments.
There are other ways of doing this, for sure, such as toLocaleString(), but this fit my exact requirements. Hopefully it'll help someone else.

Iterate Through Nested JavaScript Objects - Dirty?

I have some JavaScript that I wrote in a pinch, but I think it could be optimized greatly by someone smarter than me. This code runs on relatively small objects, but it runs a fair amount of times, so its worth getting right:
/**
* Determine the maximum quantity we can show (ever) for these size/color combos
*
* #return int=settings.limitedStockThreshold
*/
function getMaxDefaultQuantity() {
var max_default_quantity = 1;
if (inventory && inventory.sizes) {
sizecolor_combo_loop:
for (var key in inventory.sizes) {
if (inventory.sizes[key].combos) {
for (var key2 in inventory.sizes[key].combos) {
var sizecolor_combo = inventory.sizes[key].combos[key2];
if (isBackorderable(sizecolor_combo)) {
//if even one is backorderable, we can break out
max_default_quantity = settings.limitedStockThreshold;
break sizecolor_combo_loop;
} else {
//not backorderable, get largest quantity (sizecolor_combo or max_default_quantity)
var qoh = parseInt(sizecolor_combo.quantityOnHand || 1);
if (qoh > max_default_quantity) {
max_default_quantity = qoh;
};
};
};
};
};
};
return Math.min(max_default_quantity, settings.limitedStockThreshold);
};
First, inventory is a object returned via JSON. It has a property inventory.sizes that contain all of the available sizes for a product. Each size has a property inventory.sizes.combos which maps to all of the available colors for a size. Each combo also has a property quantityOnHand that tells the quantity available for that specific combo. (the JSON structure returned cannot be modified)
What the code does is loop through each size, then each size's combos. It then checks if the size-color combo is backorderable (via another method). If it any combo is backorderable, we can stop because the default quantity is defined elsewhere. If the combo isn't backorderable, the max_default_quantity is the largest quantityOnHand we find (with a maximum of settings.limitedStockThreshold).
I really don't like the nested for loops and my handling of the math and default values feels overly complicated.
Also, this whole function is wrapped in a much larger jQuery object if that helps clean it up.
Have you considered using map-reduce? See a live example of a functional approach.
This particular example uses underscore.js so we can keep it on a elegant level without having to implement the details.
function doStuff(inventory) {
var max = settings.limitedStockThreshold;
if (!(inventory && inventory.sizes)) return;
var quantity = _(inventory.sizes).chain()
.filter(function(value) {
return value.combos;
})
.map(function(value) {
return _(value.combos).chain()
.map(function(value) {
return isBackorderable(value) ? max : value.quantityOnHand;
})
.max().value();
})
.max().value();
return Math.min(quantity, max);
}
As for an explanation:
We take the inventory.sizes set and remove any that don't contain combos. We then map each size to the maximum quantity of it's colour. We do this mapping each combo to either its quantity or the maximum quantity if backordable. We then take a max of that set.
Finally we take a max of set of maxQuantities per size.
We're still effectily doing a double for loop since we take two .max on the set but it doesn't look as dirty.
There are also a couple of if checks that you had in place that are still there.
[Edit]
I'm pretty sure the above code can be optimized a lot more. but it's a different way of looking at it.
Unfortunately, JavaScript doesn't have much in the way of elegant collection processing capabilities if you have to support older browsers, so without the help of additional libraries, a nested loop like the one you've written is the way to go. You could consider having the values precomputed server-side instead, perhaps cached, and including it in the JSON to avoid having to run the same computations again and again.

Categories

Resources