Code suggestions - using $.each() to set a kind of use meter - javascript

Hoping for a quick peer review here. An associate and I build out a video popchart plugin for a client in south korea (here's the test site - http://izepic.com/kpopcharts/). My question relates to the activity meter in the header of each vid player. So, I wrote the js below to check each of the social interaction numbers, determine their percentage of the interaction total, and then set the width of each type in the meter itself. Note, specificity for each interaction type was required.
$('.bkp-meter').each(function(index){
// find participation type base numbers
var voteTotal = parseInt($('.bkp-vote-total').eq(index).text());
var facebookTotal = parseInt($('.bkp-facebook-total').eq(index).text());
var twitterTotal = parseInt($('.bkp-twitter-total').eq(index).text());
var googleTotal = parseInt($('.bkp-google-total').eq(index).text());
var commentTotal = parseInt($('.bkp-comment-total').eq(index).text());
var scoreTotal = voteTotal + facebookTotal + twitterTotal + googleTotal + commentTotal;
// find participation type ratio
var votePercentage = (voteTotal / scoreTotal) * 100;
var facebookPercentage = (facebookTotal / scoreTotal) * 100;
var twitterPercentage = (twitterTotal / scoreTotal) * 100;
var googlePercentage = (googleTotal / scoreTotal) * 100;
var commentPercentage = (commentTotal / scoreTotal) * 100;
if(scoreTotal > 2) {
// set meter widths for each participation type
$('.bkp-meter-votes').eq(index).css('width', (votePercentage.toFixed(0) - 2) + "%");
$('.bkp-meter-fb').eq(index).css('width',facebookPercentage.toFixed(0) + "%");
$('.bkp-meter-twitter').eq(index).css('width',twitterPercentage.toFixed(0) + "%");
$('.bkp-meter-google').eq(index).css('width',googlePercentage.toFixed(0) + "%");
$('.bkp-meter-comments').eq(index).css('width',(commentPercentage.toFixed(0)) + "%");
} else {
$(this).parent().parent().addClass('novotes');
}
});
My question: is there a quicker, cleaner way to do this? I mean, it's working fine so problem solved but it feels very brute force ... for my own improvement I'd like to know if there's a more efficient method and what sort of issues I might run into with this. One note - the percentages didn't have to be perfect ... they just need to give the user a quick shot of what other people are doin' with that vid.
Thanks

As a programmer, you should generalize when there is more than one thing:
var participationTypes = ['vote', 'facebook', 'twitter', 'google', 'comment'];
$('.bkp-meter').each(function() {
var meter = $(this);
var scores = {};
var scoreTotal = 0;
$.each(participationTypes, function() {
scores[this] = parseInt(meter.find('.bkp-'+this+'-total').text());
scoreTotal += scores[this];
});
if(scoreTotal > 2)
$.each(participationTypes, function() {
meter.find('.bkp-meter-'+this).width(
Math.round(scores[this] / scoreTotal * 100) + '%'
);
});
else
meter.parent().parent().addClass('novotes');
});

$.each() returns two params, one is index and the other is the object itself. You can optimize your selectors by only searching within that context.
$('.bkp-meter').each(function(index, meter){
...
$('.bkp-meter-votes', meter).css('width', (votePercentage.toFixed(0) - 2) + "%");
$('.bkp-meter-fb', meter).css('width',facebookPercentage.toFixed(0) + "%");
...
});
Same thing applies to your first block with the $('.bkp-vote-total').eq(index) bits.
Also note that class selectors are really slow in browsers that don't support getElementByClass natively (namely IE8 and lower) so beware using them alone like that if it's a concern. Always provide context: $('#container .bkp-meter')

Related

Isolating a part of a string

well... for begining, i m building some dumb and easy projects because i'm starting learning the world of front end development. One of those you can find in internet was this Color picker idea. Some page where with a button you can generate a random color. all random, no connections between the colors o something else.
(i'm not a native english speaker so sorry if i write something and you dont get it right)
Here's the link to the repository
so...
I build a function that makes a random HSL color randomizing the values and then building a string and puting that in the css
function getRandomHsl(){
let hueValue = 0;
hueValue = Math.floor(
Math.random() * (360 + 1)
)
let satValue = 0;
satValue = Math.floor(
Math.random() * (100 + 1)
)
let lightValue = 0;
lightValue = Math.floor(
Math.random() * (100 + 1)
)
return 'hsl(' + hueValue + ', ' + satValue + '%, ' + lightValue + '%)';}
if you can give me your opinion on that function and tell me if you would have done it inanother way.
so... i wanted to find the way to if the Lightness would have a low value the color of the font change it to some white or something like that. And this is what i figured out. (the first part of the code is the button changing the value of the background color of the main div. This works well. The problem comes after).
hslBtn.addEventListener('click', () => {
let hslStringComplete = getRandomHsl();
colorShowcase.textContent = hslStringComplete;
document.getElementById('color-container').style.backgroundColor = hslStringComplete;
/*================================= change the color font od the text when its to dark */
let hslLightValue = hslStringComplete;
let lightValue = hslLightValue.toString().substr(13,3).replace(/\D/g,'')
console.log(hslLightValue.substr(13,3).replace(/\D/g,''));
if(lightValue < 40){
innerHTML('input').style.color = "white";
}})
i have really strougle it out coming up with this idea so i want some opinion on how could i have done in other way.
PD: `if(lightValue < 40){
innerHTML('input').style.color = "white";}
this is hte HTML: <input class="background-container"><h3 class="forWhiteColor">Background Color : <span class="color-showcase">#messi</span></h3></input>
this part get me an error and the html doesn get changes. Here's the error.
console error
thanks in advance.
innerHTML('input') should probably be document.getElementById('color-container') instead.
also you should note that when you extract a part of a string, you get a string.
And comparing a string to a number won't work well, you first need to convert your string to a number with parseInt (for integers) or parseFloat (for float)

Is there a good inline solution to add up without going above a defined value?

For some reasons i need to reduce the size of my application, and i'm pretty sure there is a way to free room. So, is there a smarter way to do this without making usage of an if ?
currentMoney = 46;
maximumMoney = 100;
moneyIncome = 72;
currentMoney = currentMoney + moneyIncome;
if (currentMoney > maximumMoney)
currentMoney = maximumMoney;
You could use a minimum function, for example in javascript:
currentMoney = Math.min(currentMoney + moneyIncome, maximumMoney);
or C#:
currentMoney = Math.Min(currentMoney + moneyIncome, maximumMoney);

random numbers across different browsers

I would like to assign each visitor a random number in order to enable stuff like A/B-testing etc. I also would like to generate the number on the client - not the server. And since it should be fast I would like to use Math.random()
My question now is the following: Do I get a random distribution of numbers or will different implementations skew the numbers?
Cheers
Valentin
You can use the follow javascript to test the effective random distribution of javascript's Math.random:
var totalAbove =0;
var totalBelow = 0
for(var i=0;i<10000;i++){
var randomNumber = Math.ceil(Math.random()*1000)
if(randomNumber > 500){
totalAbove++
}else{
totalBelow++
}
}
var belowSplit = (totalBelow / 10000) * 100
var aboveSplit = (totalAbove / 10000 ) * 100
alert("Above 500: " + totalAbove + "\n" + "Below 500: " + totalBelow + "\n split: " + belowSplit + "/" + aboveSplit);
or use this jsfiddle: http://jsfiddle.net/VN3Bd/
You can try it across different browsers to see if it behaves differently, but I think you'll see that the distribution is quite even.
I think you can rely on Math.random for this job.
In general, implementations of 'Math.random()' on client side should be good enough for the random distribution as well as if it was your server that generate them. But you can not be sure.

jquery: percentage of two numbers (Part 2)

this is continuation of last successful topic
jquery: percentage of two numbers
First of all I want to thank you for your prompt support of previuous post.
Now I would like to make my script a little bit more complicated. I want to achive the following: If I insert PRICE1 and PRICE2 to have RATE between THEM, then I can change the RATE with other value and PRICE2 to change to the corespondent value according to RATE value.
My script of calculation is close to be correct, but my low knowledge about JQuery make me to ask you where I do something wrong.
Thank you for your support!
<script src="libs/jquery.min.js"></script>
<script type="text/javascript">
$(function() {
$("#PRICE1, #PRICE2").change(function() {
var result = parseFloat(parseFloat($("#PRICE1").val(), 10) - parseFloat($("#PRICE1").val(), 10))/ parseFloat($("#PRICE2").val(), 10) * 100;
$('#RATE').val(result||'');
})
else {
$("#PRICE1, #RATE").change(function() {
var result = parseFloat(parseFloat($("#PRICE1").val(), 10) * parseFloat($("#RATE").val(), 10))/ 100 + parseFloat($("#PRICE1").val(), 10);
$('#PRICE2').val(result||'');
})}
});
</script>
EDITED:
THE CODE ALMOST WORKING CORRECTLY WHICH MIGHT HELP OTHERS:
$(document).ready(function(){
$("#priceOne, #priceTwo").change(function() {
var priceOne = parseFloat($("#priceOne").val());
var priceTwo = parseFloat($("#priceTwo").val());
$('#Rate').val((priceTwo - priceOne) / priceOne * 100); // Set the rate
});
// If price one or the rate is changed, adjust price two.
$("#priceOne, #RATE").change(function() {
var priceOne = parseFloat($("#priceOne").val());
var rate = parseFloat($("#Rate").val());
$('#priceTwo').val((priceOne * rate)/ 100 + priceOne);
});
})
Thank you everyone who help me!!!
There is a else and no matching if. I'm not sure what you're trying to achieve, but some condition needs to be checked.
I'm going to try and code what it appears you need. But I'm going to rename your variables, not only because allcaps are hard to type, but unless it's a constant or a macro, they shouldn't be used.
// In ready() callback
// #NOTE - This does NO error checking for division by 0 or other NaN operations.
// If price two is changed, adjust the rate.
$("#priceTwo").change(function() {
var priceOne = parseFloat($("#priceOne").val());
var priceTwo = parseFloat($(this).val());
$("#rate").val(priceTwo / priceOne); // Set the rate
});
// If price one or the rate is changed, adjust price two.
$("#rate #priceOne").change(function() {
var priceOne = parseFloat($("#priceOne").val());
var rate = parseFloat($("#rate").val());
$("#priceTwo").val(priceOne * rate);
});
There are a few things about your code that needs attention:
parseFloat doesn't take a radix argument, the 10 you pass it is ignored.
parseFloat(parseFloat(... is pointless, I'm not sure why you've done this.
Don't use jQuery to select the same element multiple times in the same scope. Save the value and re-use it - save yourself some cycles.
As I mentioned, don't name your variables in all capitals unless they are some sort of constant that should never be changed, it's good to have clean style habits.

How to find the size of localStorage

I am currently developing a site that will make use of HTML5's localStorage. I've read all about the size limitations for different browsers. However, I haven't seen anything on how to find out the current size of a localStorage instance. This question seems to indicate that JavaScript doesn't have a built in way of showing the size for a given variable. Does localStorage have a memory size property that I haven't seen? Is there an easy way to do this that I'm missing?
My site is meant to allow users to enter information in an 'offline' mode, so being able to give them a warning when the storage is almost full is very important.
Execute this snippet in JavaScript console (one line version):
var _lsTotal=0,_xLen,_x;for(_x in localStorage){ if(!localStorage.hasOwnProperty(_x)){continue;} _xLen= ((localStorage[_x].length + _x.length)* 2);_lsTotal+=_xLen; console.log(_x.substr(0,50)+" = "+ (_xLen/1024).toFixed(2)+" KB")};console.log("Total = " + (_lsTotal / 1024).toFixed(2) + " KB");
The same code in multiple lines for reading sake
var _lsTotal = 0,
_xLen, _x;
for (_x in localStorage) {
if (!localStorage.hasOwnProperty(_x)) {
continue;
}
_xLen = ((localStorage[_x].length + _x.length) * 2);
_lsTotal += _xLen;
console.log(_x.substr(0, 50) + " = " + (_xLen / 1024).toFixed(2) + " KB")
};
console.log("Total = " + (_lsTotal / 1024).toFixed(2) + " KB");
or add this text in the field 'location' of a bookmark for convenient usage
javascript: var x, xLen, log=[],total=0;for (x in localStorage){if(!localStorage.hasOwnProperty(x)){continue;} xLen = ((localStorage[x].length * 2 + x.length * 2)/1024); log.push(x.substr(0,30) + " = " + xLen.toFixed(2) + " KB"); total+= xLen}; if (total > 1024){log.unshift("Total = " + (total/1024).toFixed(2)+ " MB");}else{log.unshift("Total = " + total.toFixed(2)+ " KB");}; alert(log.join("\n"));
P.S. Snippets are updated according to request in the comment. Now the calculation includes the length of the key itself.
Each length is multiplied by 2 because the char in javascript stores as UTF-16 (occupies 2 bytes)
P.P.S. Should work both in Chrome and Firefox.
Going off of what #Shourav said above, I wrote a small function that should accurately grab all your the localStorage keys (for the current domain) and calculate the combined size so that you know exactly how much memory is taken up by your localStorage object:
var localStorageSpace = function(){
var allStrings = '';
for(var key in window.localStorage){
if(window.localStorage.hasOwnProperty(key)){
allStrings += window.localStorage[key];
}
}
return allStrings ? 3 + ((allStrings.length*16)/(8*1024)) + ' KB' : 'Empty (0 KB)';
};
Mine returned: "30.896484375 KB"
You can get the current size of the local storage data using the Blob function. This may not work in old browsers, check the support for new Blob and Object.values() at caniuse.
Example:
return new Blob(Object.values(localStorage)).size;
Object.values() turns the localStorage object to an array. Blob turns the array into raw data.
IE has a remainingSpace property of the Storage object. The other browsers have no equivalent at this time.
I believe that the default amount of space is 5MB, although I have not tested it personally.
Here is a simple example of how to do this and should work with every browser
alert(1024 * 1024 * 5 - unescape(encodeURIComponent(JSON.stringify(localStorage))).length);
Hope this help someone.
Because Jas- example on jsfiddle does not work for me I came up with this solution.
(thanks to Serge Seletskyy and Shourav for their bits I used in the code below)
Below is the function that can be used to test how much space is available for localStorage and (if any keys are already in lS) how much space is left.
It is a little brute force but it works in almost every browser... apart from Firefox.
Well in desktop FF it takes ages (4-5min) to complete, and on Android it just crashes.
Underneath the function is a short summary of tests that I have done in different browsers on different platforms. Enjoy!
function testLocalStorage() {
var timeStart = Date.now();
var timeEnd, countKey, countValue, amountLeft, itemLength;
var occupied = leftCount = 3; //Shurav's comment on initial overhead
//create localStorage entries until localStorage is totally filled and browser issues a warning.
var i = 0;
while (!error) {
try {
//length of the 'value' was picked to be a compromise between speed and accuracy,
// the longer the 'value' the quicker script and result less accurate. This one is around 2Kb
localStorage.setItem('testKey' + i, '11111111112222222222333333333344444444445555555555666661111111111222222222233333333334444444444555555555566666');
} catch (e) {
var error = e;
}
i++;
}
//if the warning was issued - localStorage is full.
if (error) {
//iterate through all keys and values to count their length
for (var i = 0; i < localStorage.length; i++) {
countKey = localStorage.key(i);
countValue = localStorage.getItem(localStorage.key(i));
itemLength = countKey.length + countValue.length;
//if the key is one of our 'test' keys count it separately
if (countKey.indexOf("testKey") !== -1) {
leftCount = leftCount + itemLength;
}
//count all keys and their values
occupied = occupied + itemLength;
}
;
//all keys + values lenght recalculated to Mb
occupied = (((occupied * 16) / (8 * 1024)) / 1024).toFixed(2);
//if there are any other keys then our 'testKeys' it will show how much localStorage is left
amountLeft = occupied - (((leftCount * 16) / (8 * 1024)) / 1024).toFixed(2);
//iterate through all localStorage keys and remove 'testKeys'
Object.keys(localStorage).forEach(function(key) {
if (key.indexOf("testKey") !== -1) {
localStorage.removeItem(key);
}
});
}
//calculate execution time
var timeEnd = Date.now();
var time = timeEnd - timeStart;
//create message
var message = 'Finished in: ' + time + 'ms \n total localStorage: ' + occupied + 'Mb \n localStorage left: ' + amountLeft + "Mb";
//put the message on the screen
document.getElementById('scene').innerText = message; //this works with Chrome,Safari, Opera, IE
//document.getElementById('scene').textContent = message; //Required for Firefox to show messages
}
And as promised above some test in different browsers:
GalaxyTab 10.1
Maxthon Pad 1.7 ~1130ms 5Mb
Firefox 20.0(Beta 20.0) crashed both
Chrome 25.0.1364.169 ~22250ms /5Mb
Native (identifies as Safari 4.0/Webkit534.30) ~995ms /5Mb
iPhone 4s iOS 6.1.3
Safari ~ 520ms /5Mb
As HomeApp ~525ms / 5Mb
iCab ~ 710ms /5mb
MacBook Pro OSX 1.8.3 (Core 2 Duo 2.66 8Gb memory)
Safari 6.0.3 ~105ms /5Mb
Chrome 26.0.1410.43 ~3400ms /5Mb
Firefox 20.0 300150ms(!) /10Mb (after complaining about script running to long)
iPad 3 iOS 6.1.3
Safari ~430ms /5Mb
iCab ~595ms /5mb
Windows 7 -64b (Core 2 Duo 2.93 6Gb memory)
Safari 5.1.7 ~80ms /5Mb
Chrome 26.0.1410.43 ~1220ms /5Mb
Firefox 20.0 228500ms(!) /10Mb (after complaining about script running to long)
IE9 ~17900ms /9.54Mb ( if any console.logs are in the code does not work until DevTools are opened)
Opera 12.15 ~4212ms /3.55Mb (this is when 5Mb is selected, but Opera asks nicely if we want increase the amount of lS, unfortunately it crashes if test conducted a few times in a row)
Win 8 (Under Parallels 8)
IE10 ~7850ms /9.54Mb
You can calculate your localstorage by following methods:
function sizeofAllStorage(){ // provide the size in bytes of the data currently stored
var size = 0;
for (i=0; i<=localStorage.length-1; i++)
{
key = localStorage.key(i);
size += lengthInUtf8Bytes(localStorage.getItem(key));
}
return size;
}
function lengthInUtf8Bytes(str) {
// Matches only the 10.. bytes that are non-initial characters in a multi-byte sequence.
var m = encodeURIComponent(str).match(/%[89ABab]/g);
return str.length + (m ? m.length : 0);
}
console.log(sizeofAllStorage());
Finally size in bytes will be logged in browser.
I would use the code of #tennisgen which get all and count the content, but I count the keys themselves:
var localStorageSpace = function(){
var allStrings = '';
for(var key in window.localStorage){
allStrings += key;
if(window.localStorage.hasOwnProperty(key)){
allStrings += window.localStorage[key];
}
}
return allStrings ? 3 + ((allStrings.length*16)/(8*1024)) + ' KB' : 'Empty (0 KB)';
};
The way I went about this problem is to create functions for finding out the used space and remaining space in Local Storage and then a function that calls those functions to determine the max storage space.
function getUsedSpaceOfLocalStorageInBytes() {
// Returns the total number of used space (in Bytes) of the Local Storage
var b = 0;
for (var key in window.localStorage) {
if (window.localStorage.hasOwnProperty(key)) {
b += key.length + localStorage.getItem(key).length;
}
}
return b;
}
function getUnusedSpaceOfLocalStorageInBytes() {
var maxByteSize = 10485760; // 10MB
var minByteSize = 0;
var tryByteSize = 0;
var testQuotaKey = 'testQuota';
var timeout = 20000;
var startTime = new Date().getTime();
var unusedSpace = 0;
do {
runtime = new Date().getTime() - startTime;
try {
tryByteSize = Math.floor((maxByteSize + minByteSize) / 2);
//localStorage.setItem(testQuotaKey, new Array(tryByteSize).join('1'));
//Recommended by #pkExec and #jrob007
localStorage.setItem(testQuotaKey, String('1').repeat(tryByteSize));
minByteSize = tryByteSize;
} catch (e) {
maxByteSize = tryByteSize - 1;
}
} while ((maxByteSize - minByteSize > 1) && runtime < timeout);
localStorage.removeItem(testQuotaKey);
if (runtime >= timeout) {
console.log("Unused space calculation may be off due to timeout.");
}
// Compensate for the byte size of the key that was used, then subtract 1 byte because the last value of the tryByteSize threw the exception
unusedSpace = tryByteSize + testQuotaKey.length - 1;
return unusedSpace;
}
function getLocalStorageQuotaInBytes() {
// Returns the total Bytes of Local Storage Space that the browser supports
var unused = getUnusedSpaceOfLocalStorageInBytes();
var used = getUsedSpaceOfLocalStorageInBytes();
var quota = unused + used;
return quota;
}
In addition to #serge's answer which is most voted here, size of the keys need to be considered. Code below will add the size of the keys stored in localStorage
var t = 0;
for (var x in localStorage) {
t += (x.length + localStorage[x].length) * 2;
}
console.log((t / 1024) + " KB");
As the spec goes, each character of a string is 16 bit.
But inspecting with chrome (Settings>Content Settings>Cookies & Site data) shows us that initiating localStorage takes 3kB (overhead size)
And stored data size follows this relation (accurate to 1kB)
3 + ((localStorage.x.length*16)/(8*1024)) kB
where localStorage.x is your storage string.
Yes, this question was asked like 10 years ago. But for those interested (like myself, as I am building an offline text editor that saves data with local storage) and suck at programming, you could use something simple like this:
var warning = 1;
var limit = 2000000; //2 million characters, not really taking in account to bytes but for tested number of characters stored
setInterval(function() {
localStorage["text"] = document.getElementById("editor").innerHTML; //gets text and saves it in local storage under "text"
if(localStorage["text"].length > limit && warning == 1){
alert("Local Storage capacity has been filled");
warning = 2; //prevent a stream of alerts
}
}, 1000);
//setInterval function saves and checks local storage
The best way to get the amount of storage filled is to view the site settings (say, if you stored an image in local storage). At least in chrome, you can see the amount of bytes used (ie: 1222 bytes). However, the best ways to see filled local storage with js have already been mentioned above, so use them.
//Memory occupy by both key and value so Updated Code.
var jsonarr=[];
var jobj=null;
for(x in sessionStorage) // Iterate through each session key
{
jobj={};
jobj[x]=sessionStorage.getItem(x); //because key will also occupy some memory
jsonarr.push(jobj);
jobj=null;
}
//https://developer.mozilla.org/en/docs/Web/JavaScript/Data_structures
//JavaScript's String type is used to represent textual data. It is a set of "elements" of 16-bit unsigned integer values.
var size=JSON.stringify(jsonarr).length*2; //16-bit that's why multiply by 2
var arr=["bytes","KB","MB","GB","TB"]; // Define Units
var sizeUnit=0;
while(size>1024){ // To get result in Proper Unit
sizeUnit++;
size/=1024;
}
alert(size.toFixed(2)+" "+arr[sizeUnit]);
window.localStorage.remainingSpace

Categories

Resources