I am developing a application with phonegap. on my pc everything runs fine but on my mobile device its just too slow.
i think the problem is on the show function, the android browser seems to needs really long to hide and show elements
what can be improved?
function show(id){
$('.view').hide()
//alert('show ' + id)
$('#'+id+'View').show()
scroll(0,0)
}
function getSoundHTML(id, myname, del){
if (del != true){
var imgsrc = 'plus.png'
var f = function(){
addToCostumSounds(id)
alert('added to favorites')
}
}else{
var imgsrc = 'minus.png'
var f = function(){
removeFromCostumSounds(id);
$(this).fadeOut().next('div').fadeOut();
}
}
var div = $('<div></div>').addClass('box').html(myname).css('border-color', '999999').click(function(){
play(id)
})
var img = $('<img></img>').attr('src', imgsrc).addClass('sideimg').click(f)
return $('<div></div>').append(img).append(div)
}
for(var category in categories){
var f = function(category){
$('#'+category+'Btn').click(function(){
show(category)
var categoryView = $('#'+category+'View')
for(var key in categories[category]){
var div = getSoundHTML(key, categories[category][key])
categoryView.prepend(div)
}
var img = '<img src="menu.png" class="menuimg"/>'
categoryView.prepend(img)
categoryView.append(img)
})
}
f(category)
}
the html:
<div class="btn" id="noBtn">no _</div>
<div class="btn" id="thatIsBtn">that is _</div>
<div class="btn" id="thereIsBtn">there is _</div>
<div class="btn" id="thisIsBtn">this is _</div>
...
<div class="view" id="noView"></div>
<div class="view" id="thatIsView"></div>
<div class="view" id="thereIsView"></div>
<div class="view" id="thisIsView"></div>
...
Whilst it may not have an effect on Desktops, your massive lack of semi-colons in the right places may have an effect on mobile devices.
The JavaScript engine has to run through and try to work out where the semi-colons need to go. See this transcript from the ECMAScript specification.
To be honest I think thats only a few milliseconds of time-saved, but its a starting point for now - and good practice for the future.
Here's your problem:
for(var category in categories){
var f = function(category){
...
for(var key in categories[category])
...
}
f(category)
}
You have two BIG issues here:
You're defining a function within a loop. While this is sometimes needed, you should do your very best to avoid defining things within a loop unless you absolutely need to. In this case, you could probably move the f function out of the loop entirely without breaking your code.
Nested loops. You have a for ... in within a for ... in loop. This is largely due to the first problem I pointed out, but in general nested loops are a big no-no from a performance standpoint.
ok, i think i got the only way to improve the peroformance:
if someone clicks on a button (class="btn") he is redirected to a new fresh page that has the entire page in HTML and does not build it with javascript.
Related
I am a very novice coder and I am creating a game that calculates the area of a given rectangle however once the page loads, the image does not show and thus the user cannot answer the question.
An example image has been copied below
The "score" does not display either. Any help would be greatly appreciated :)
var number1;
var number2;
var response;
var calcanswer;
var score = 0;
window.onload = areaquestion1;
myScore.text = "SCORE: " + score;
function areaquestion1() {
var question = document.createElement("question");
question.setAttribute("src", "Images/2*1.png");
question.setAttribute("width", "304");
question.setAttribute("height", "228");
question.setAttribute("alt", "2*1");
document.body.appendChild(question);
var number1 = 2
var number2 = 1
calcanswer = (number1*number2);
var question = document.getElementById("question");
question.innerHTML = "What is the area of this lego brick?";
check();
areaquestion2();
}
function areaquestion2() {
var question = document.createElement("question");
question.setAttribute("src", "Images/3*2.png");
question.setAttribute("width", "304");
question.setAttribute("height", "228");
question.setAttribute("alt", "3*2");
document.body.appendChild(question);
var number1 = 3
var number2 = 2
calcanswer = (number1*number2);
var question = document.getElementById("question");
question.innerHTML = "What is the area of this lego brick?";
check();
areaquestion3();
}
function check()
{
var statusDiv = document.getElementById("status");
response=document.getElementById("answer").value;
if(response != calcanswer)
statusDiv.innerHTML="Incorrect";
else
if (response==calcanswer)
{
statusDiv.innerHTML="Very good!";
score ++;
document.getElementById("score").textContent = score
document.getElementById("answer").value = "";
problem();
}
}
<!DOCTYPE html>
<html>
<title>Lego Area</title>
<head>
<link rel="stylesheet" href="CSS/Play.css">
<script src="JavaScript/Play.js"></script>
</head>
<body onload="areaquestion1();">
<div class="header">
<h1>LEGO AREA</h1>
<p>Calculating <b>area</b> with Emmet.</p>
<div id="score" class="score" value="SCORE:"></div>
</div>
<form>
<div class="row">
<div class="side">
<div id="question"></div>
<div id ="prompt"></div>
<input type="text" id="answer"/>
</div>
<div class="main">
<input id="solve" type="button" value="CHECK!" onclick="check()" />
</div>
</div>
</form>
<div id="status"></div>
<!-- Footer -->
<div class="footer">
<div class="practice"> <img src="Images/legoBlue2.png" id="practicebtn" width="20%"></div>
<div class="play"> <img src="Images/legored2.png" id="playbtn" width="20%"></div>
</div>
</body>
</html>
This is my first question I'm attempting to answer -- so pretty big deal. Anyway...
A few things I noticed:
I got pretty confused reading the code seeing the question variable being used so much for different parts of the code. So I changed the var question to var imageBlock to make it more readable for me.
You were running the areaquestion1() function onload. Since the check() function was run as a part of the areaquestion1() function it was being run as well, in-turn displaying 'Incorrect' even before an answer was entered. I changed this to document.getElementById("solve").check(); to ensure it runs only after the CHECK! button was clicked.
Finally getting to your actual question. It looks like you are trying to use document.createElement to create an image with an id of question, however based on geeks for geeks and W3 Schools you use the document.createElement to create the img element. THEN you can set the id attribute to whatever you like. In this case, I switched it to imageBlock.setAttribute("id", "madeUpImg"); to help with my readability.
So this is what I did, I think there are a lot of improvements you can make, but this works and it will give you a good start:
function areaquestion1() {
var imageBlock = document.createElement("IMG");
imageBlock.setAttribute("id", "madeUpImg");
imageBlock.setAttribute("src", "guWFE.png");
imageBlock.setAttribute("width", "304");
imageBlock.setAttribute("height", "228");
imageBlock.setAttribute("alt", "2*1");
document.body.appendChild(imageBlock); // this appends it to the bottom of the page
number1 = 2
number2 = 1
calcanswer = (number1*number2);
var question = document.getElementById("question");
question.innerHTML = "What is the area of this lego brick?";
document.getElementById("solve").check();
// areaquestion2(); }
All of this is edited to address your further questions:
For appending it in the appropriate spot: I haven't had time to jump back in my code, but this is what I'm thinking. Currently, when you read your code you have document.body.appendChild(question); This JavaScript is telling the computer to find the document, then find the body of that document, then run the appendChild function. So, basically it is saying - "computer, append the question variable to the body of the document". So, what's wrong with this? Well, you want to append it to a specific div! So, you're extremely close, but you're not grabbing the question div! You need to use code to tell the computer to find the question div, then append the image to that div. I'd do something like this: document.getElementById('question').appendChild(imageBlock) this now means the code is grabbing onto the div that you want to append it to then, appending the imageBlock to that div.
I commented out that areaquestion2 because I know you're going to run into more problems. 1. If you call the areaquestion2in the areaquestion1 function it will run immediately when the website loads (you're calling the area question1 on load). I think this is going to make both images appear at the same time. Why? It is just being instructed to append another image to the question div. 2. You probably don't want both images appearing at the same time. So, you're going to need to find a way to replace the first image rather then trying to add another one.
That's about all I can help you with on this for now. I think that if you continue to work through this then refactor it, you're going to learn a ton. I think you should try to bring this to one function by assigning questions to variables, then passing those variables in as arguments to your function. If you haven't already, I'd highly recommend going through FreeCodeCamp's stuff lesson by lesson.
Hope this helped!!
Good evening,
I have many articles on my web (my own do-it-yourself manuals how to create...) interspersed with pictures (it is written in Czech language). These pictures are small and I want using onclick in html to display them bigger always close to those small. I.e. each bigger picture is to be displayed beside his small one. This is a practical illustration:
http://mix.zlatberry.cz/obrazky1.html (clicking on the big picture - unintentionally at the end of site - it is shut down).
But, clicking any small picture only the last big picture is displayed!
Currently I know that only so called closure is remedy for my problem but despite this trick I am not able to force my iteration to show the first big picture beside the first small one, the second big picture beside the second small one and so on and so on.
HTML (is not from my head). Btw, please, is it posible to write this code - small picture versus big picture - easier way??
let obr = new Array('velka-fotka1', 'velka-fotka2', 'velka-fotka3', 'velka-fotka4', 'velka-fotka5');
for (let i = 0; i < obr.length; i++) {
(function() {
let x = i;
let fotka = document.getElementById(obr[x]);
function ZobrazFotku() {
fotka.style.display = 'block';
}
document.write(x); //document.write(x) writes numbers 01234
function SchovatFotku(div) {
document.getElementById(div).style.display = 'none';
}
})();
}
<div id='velka-fotka1'>
<div class="foto">
<a href='#' onclick="SchovatFotku('velka-fotka1'); return false" title='Shut down'></a>
<img src='bigmotopelech1.jpg' alt='click for display small picture' onclick="SchovatFotku('velka-fotka1'); return false" />
</div>
</div>
<div class="foto">
<a onclick="ZobrazFotku('bigmotopelech1.jpg'); return false" href='bigmotopelech1.jpg' title='display the big picture'><img src='motopelech1.jpg' width="320" height="240" alt="Pneumatika z motorky a deka"></a>
</div>
Testing my closure I tried to add document.write(x) but numbers are listed TOGETHER, not one after another by clicking small pictures, and all big pictures are displayed, to make thing worse, in a separate window of browser:
http://mix.zlatberry.cz/obrazky2.html
So I am really at the end of my tether :-( . I try to solve it since September.
I will be very appreciative for help leading to solving my problem. I enjoy to modify all my websites this way and I am in the doldrums...
Many thanks in advance <3
HTML:
<div id='big-photo1'>
<div class="foto">
<a href='#' onclick="HidePhoto('big-photo1'); return false" title='Hide'></a>
<img src='bigmotopelech1.jpg' alt='click for display a small photo' onclick="HidePhoto('big-photo1'); return false" />
</div>
</div>
<div class="foto">
<a onclick="DisplayPhoto('bigmotopelech1.jpg'); return false" href='bigmotopelech1.jpg' title='display a big photo'><img src='motopelech1.jpg' width="320" height="240" alt="Pneumatika z motorky a deka"></a>
</div>
Javascript:
let picture = new Array('big-photo1', 'big-photo2', 'big-photo3', 'big-photo4', 'big-photo5');
for (let i = 0; i < picture.length; i++) {
(function() {
let x = i;
let photo = document.getElementById(picture[x]);
function DisplayPhoto() {
photo.style.display = 'block';
}
function HidePhoto(div){
document.getElementById(div).style.display='none';
}
})();
}
Here is link with English variables etc. http://mix.zlatberry.cz/pict1.html
Change your ZobrazFotku function to accept the id of the div in which the img is contained as the first argument. This way you don't need the for loop at all.
function ZobrazFotku(id) {
var div = document.getElementById(id);
div.style.display = 'block';
}
function SchovatFotku(div) {
document.getElementById(div).style.display = 'none';
}
JSFiddle Demo: http://jsfiddle.net/rkaqzx2v/
I have made a simple zoom in and out function with button as well as mousewheel function. The main concept is to limit the maximum zoom level and minimum zoom level.
I have successfully made it in two ways
BIN 1
BIN 2
But i tried to make this in a tab section with unique ID or by class.
My script
var zoomLevel = 100;
var maxZoomLevel = 150;
var minZoomLevel = 50;
var initW=0,initH=0;
function zoom(zm) {
var img=document.getElementById("pic");
if(zm > 1){
if(zoomLevel < maxZoomLevel){
zoomLevel+=10;
}else{
return;
}
}else if(zm < 1){
if(zoomLevel > minZoomLevel){
zoomLevel-=10;
}else{
return;
}
}
img.style.width = (initW*zoomLevel/100)+"px";
img.style.height = (initH*zoomLevel/100)+"px";
img.style.marginLeft = ((initW-img.width)/2) + "px";
img.style.marginTop = ((initH-img.height)/2) + "px";
}
window.onload=function(){
var img=document.getElementById("pic");
initW=img.width;
initH=img.height;
img.onmousewheel=function(e){
e=e||window.event;
if(e.wheelDelta>=120) zoom(1.1);
else zoom(0.9);
};
if(/Firefox/.test(navigator.userAgent)){
img.addEventListener("DOMMouseScroll",function(e){
if(e.detail<0) zoom(1.1);
else if(e.detail>0) zoom(0.9);
e.preventDefault();
},false);
}
};
Here i am getting my element by using GetElementById to access my image tag is there any way to get access all the img tags in other tabs too.
I also tried getElementsbyClassName but its not working it just retrieving the nodeslist.
How can i access all three images here
Current BIN
you need to use different ID's
var img=document.getElementById("pic1");
var img=document.getElementById("pic2");`
You have assigned all three images the same id (id="pic"). You can't do that, ids must be unique.
If you change their ids, (ex: pic, pic2, pic3), and pass that in to your zoom function as an argument, then all the tabs will zoom.
So change the zoom function to look like this:
function zoom(zm, id) {
var img=document.getElementById(id);
...
}
And make your html look like this (just one for an example):
<div id="tabs-2">
<input type="button" value ="-" onClick="zoom(0.9, 'pic2')"/>
<input type="button" value ="+" onClick="zoom(1.1, 'pic2')"/>
<div id="thediv">
<img id="pic2" src="http://stereo-ssc.nascom.nasa.gov/beacon/t0193.jpg"/>
</div>
</div>
Now all three will zoom individually. Here's a jsbin showing it.
But, there's a bug. The variable you use to track the zoom state is being shared between the tabs. This means the "zoom limit" is not really enforced: you can just zoom one tab all the way down, then the next tab all the way up. Repeat this to make any of the images as big or as small as you want. I don't think this is what you want, but I'm going to leave it an exercise for you to fix.
I have a javascript function that filter dom elements based on a input text changes, so:
$(".input").keyup(function(e) {
filter();
});
var cache = $(".dom");
var filter = function() {
cache.each(function() {
// if field contains some text show else hide
}
};
My problem happens when there are many dom elements to filter, the whole pages gets inaccessible because of the synchronous processing (like the example above). Im trying to come out with a solution that dont locks the entire page with synchronous processing.
The problem is NOT related to the filter logic (it's completely trivial), it's NOT related to the jquery or javascript itslef, it's related to the synchronous processing and the quantity of dom elements.
As JavaScript is single threaded, the only real way to sort this out is to split the long-running job into a series of shorter jobs, and use setTimeout() with a short time delay at the end of each section to kick off the next one. This gives your UI and other JavaScript events a chance to update.
You can update large set of dom nodes by placing them in a queue and process only a few elements on each setTimeout "tick". In pseudo-code:
on(event):
queue = DOM nodes to be updated
setTimeout(update)
update:
queue.slice(0, limit).each(...update a node...)
queue = queue.slice(limit) // remove processed nodes
if (queue.length > 0) setTimeout(update) // repeat...
See http://jsfiddle.net/Etsmm/2/ for a complete working example.
Upd: The first version had problems with Chrome (related to its' "display" bug), adding a fix as per this answer appears to have done the trick.
Or doing it elsewhere through an ajax request if's really too long ?
And, maybe, some kind of: first step, select all IDs to be hidden in an array, then, settimeout, then in a second step, hiding them like 50 per 50 ?
Also, maybe processing that having the container of all those elements himself hidden, and then, once done, reshowing it may be faster ?
For this kind of purposes I generally prefer Ben Alman's message queuing library. It has also different alternatives. This one is quite successful on throttling.
https://github.com/cowboy/jquery-message-queuing/
Here below a throttling sample
http://benalman.com/code/projects/jquery-message-queuing/examples/throttling/
thank you all for your help. I came up with a solution based on Ben Clayton response, but Im still looking for ideas and investigating the thg435 solution. Any comments will be apreciated.
<script type="text/javascript">
$(document).ready(function () {
var cache = $(".whatever");
var wait = 0;
var input = $("#input");
var regex = null;
input.keyup(function (e) {
go.index = 0;
clearTimeout(wait);
wait = setTimeout(go.start, 500);
});
var filter = function (i) {
var one = cache.eq(i - 1);
one.text().match(regex) ? one.show() : one.hide();
go.index++;
setTimeout(go.filter, 10);
};
go = {
index: 0,
filter: function () {
go.index == 0 || go.index > cache.length ? null : filter(go.index);
},
start: function () {
go.index = 1;
var search = input.val();
search = search.replace(new RegExp("[a]", "gi"), "[aàáâã]");
search = search.replace(new RegExp("[e]", "gi"), "[eéê]");
search = search.replace(new RegExp("[i]", "gi"), "[ií]");
search = search.replace(new RegExp("[o]", "gi"), "[oóô]");
search = search.replace(new RegExp("[u]", "gi"), "[uú]");
search = search.replace(new RegExp("[c]", "gi"), "[cç]");
regex = new RegExp(search, "gi");
go.filter();
}
}
});
</script>
<input type="text" id="input" />
<span class="whatever">lalala</span>
<span class="whatever">leléLÉ</span>
<span class="whatever">lololo</span>
<span class="whatever">lululu</span>
I really have trouble with OO coding in js. I have written a piece of code which rotates through 3 divs, and pauses on hover of any div. This code is just regular js using an array/json as the input. the code is a bit long so sorry about that. I just need some guidance on how I can convert this primitive code to a better form, as in OO and encap. When I tried myself I could not pass the slides array/json to my defined object. Is there a trick or guideline i can follow on how to rewrite this to a better form?
Edit - What is a good guideline to follow so I can rewrite this with objects instead of global variables and loose functions
var slideIndex = 0;
var prevIndex = 0;
var t;
function initPromo(){
sortSlides();
nextPromo();
addListeners();
}
function addListeners(){
for(var i=0; i<slides.length; i++)
$(slides[i].el).hover(function(){ stopPromo(); }, function(){ resumePromo(); });
}
function resumePromo(){ startTimer(); }
function stopPromo(){ clearTimeout(t); }
function nextPromo(){
if(slideIndex > 0 || prevIndex > 0) $(slides[prevIndex].el).css("display","none");
$(slides[slideIndex].el).css("display","block");
prevIndex = slideIndex;
slideIndex = (slideIndex<slides.length-1) ? slideIndex+1 : 0;
startTimer();
}
function startTimer(){ t = setTimeout("nextPromo()", 3000); }
function SortByWeight(a,b) { return b.weight - a.weight; }
function SortByWeightFr(a,b) { return b.frWeight - a.frWeight; }
function sortSlides(){
($("body.en").length > 0) ? slides.sort(SortByWeight) : slides.sort(SortByWeightFr);
}
var slides = [
{
el:'#ps1',
weight:1,
frWeight:3
},
{
el:'#ps2',
weight:0.5,
frWeight:6
},
{
el:'#ps3',
weight:4,
frWeight:9
}
];
window.onload = function () {
initPromo();
};
HTML
<body class="en">
<div id="homepageSlides">
<div id="promoSlides">
<div id="ps1">ps1</div><div id="ps2">ps2</div><div id="ps3">ps3</div>
</div>
</div>
</body>
Edit: Early days in OO coding, not asked in the right way
Well your "plain javascript" code is already taking you part way there. The first function you have defined identies the domain object: Promo.
var Promo = function () { };
You have actions on an instance of promo, init, start, stop, resume, etc. These can be defined on the prototype of Promo.
Promo.prototype.init = function() {
// ...
};
It could get a little annoying typing prototype each time, so we could bundle the prototype into a pointer that allows us a lot easier access...
var Promo = function () { };
(function(obj) {
obj.init = function() {
// ...
};
})(Promo.prototype);
So we've got some structure but we need to now separate concerns. Throughout your plain javascript you've got config type data strewn through the code. It's generally a good idea to isolate these bits of data to a single entry point for your object.
obj.init = function(_el) {
// where _el is the base element of this widget
};
I see you're also using jQuery which is good because it gives you a lot of power. One convention I like to use is instead of passing a huge amount of config data into a given widget, I like to give my objects minimal config and let them inspect the HTML to determine additional configuration data. This has the added advantage of if you wanted to add slides in the future or otherwise make changes to the slide content you need'nt worry about changing the JS.
Let's say we were to alter the slide HTML to look like...
<div id="promoSlides">
<div data-type="slide" data-slide-id="1">ps1</div>
<div data-type="slide" data-slide-id="2">ps2</div>
<div data-type="slide" data-slide-id="3">ps3</div>
</div>
Using jQuery we could identify how many slides are present.
obj.init = function(_el) {
this.baseElement = $(_el);
this.slides = this.baseElement.find('*[data-type="slide"]');
};
Now we're passing in minimal config, we've separated out the identification of the slides to the HTML, and we've got a nice pattern for a self-sufficient object. The rest would be to fill in the details (totally untested, but something like this)...
var Promo = function () { };
(function (obj) {
obj.init = function(_el, _delay) {
// Initialize markup
this.baseElement = $(_el);
this.slides = this.baseElement.find('*[data-type="slide"]');
this.slideDelay = _delay;
// Sort slides
// (not sure what's going on here)
// Bind events
this.baseElement
.on('mouseenter', this.stop.bind(this))
.on('mouseleave', this.start.bind(this));
};
obj.start = function() {
this.timer = setInterval(this.advance.bind(this), this.slideDelay);
};
obj.stop = function() {
clearInterval(this.timer);
};
obj.advance = function() {
// Slide the visible slide off screen
// (note: the parent tag will need overflow:hidden)
var visible = this.baseElement.find('*[data-type="slide"]:visible');
visible.animate({ left: '-' + (visible.width()) + 'px' }, 1000);
// Slide the next slide in
var next = visible.next();
next.css('left', this.baseElement.width() + 1).animate({ left: '0' }, 1000);
};
})(Promo.prototype);
Note that I made use of bind which isn't supported yet in older versions of IE.
Its not the converting to object oriented style what is needed for that code there.
Here are issues i see there:
pollution of global scope
mixing fixed CSS rules with Javascript
use of .length attribute within a loop
no event delegation
misplacement of <script> tag, resulting in use of window.onload
creating new jQuery object when it is not needed
use of CSS3 selectors in jQuery calls
no clue how to use setTimeout()
tight coupling to HTML ( id on each slide )