javascript push() failing - javascript

I'm trying to add cards to an array in a Deck object but for some reason push() is failing. I had this working earlier but after making some changes, I have effectively messed it up.
(The "testX" writes are there for debugging purposes)
<!DOCTYPE HTML>
<html>
<head>
<style>
#myCanvas {
border: 1px solid #9C9898;
}
body {
margin: 0px;
padding: 0px;
}
</style>
<script type="text/javascript">
<!--
//draws the game
window.onload = function() {
var canvas = document.getElementById("myCanvas");
var context = canvas.getContext("2d");
//draws the rectangles that will be the card
var cardHeight = 125,
cardWidth = 80;
context.beginPath();
//draws the top row of 5 cards
for(var x=0;x<5;x++){
context.rect(10+(x*(cardWidth+10)),10,cardWidth,cardHeight);
}
//draws the bottom row of 5 cards
for(x=0;x<5;x++){
context.rect(10+(x*(cardWidth+10)),150,cardWidth,cardHeight);
}
//draws the deck
context.rect(10+5*cardWidth+65,(150-10)/2,cardWidth,cardHeight);
context.fillStyle = 'white';
context.fill();
context.lineWidth = 2;
context.strokeStyle = 'black';
context.stroke();
};
function Deck(){
//creates the unshuffled deck (loadedDeck) once to make the shuffling process faster
var loadedDeck = new Array(),
realDeck;
this.loadTheDeck = function(){ //method
for(x=1;x<=13;x++){
this.loadedDeck.push(x+" Spades"); //<---issue line (all 4 are failing though this is the first)
this.loadedDeck.push(x+" Clubs");
this.loadedDeck.push(x+" Hearts");
this.loadedDeck.push(x+" Diamonds");
}
document.write(this.loadedDeck);
};
this.loadTheDeck(); //creates the unshuffled deck when the Deck is instantiated
//resets the deck and randomizes
this.shuffle = function(){ //method
//creates the real deck
this.realDeck = this.loadedDeck;
//write shuffle function
};
this.shuffle(); //shuffles the Deck when instantiated
}
document.write("test-1");
var myDeck = new Deck();
document.write("test0");
document.write(this.realDeck);
document.write("test1");
-->
</script>
</head>
<body>
<canvas id="myCanvas" height="300" width="600"></canvas>
</body>
</html>
Here is a demo of the code: http://jsfiddle.net/NfmsR/2/

When you run this line:
this.loadedDeck.push(x+" Spades");
You are using the this.loadedDeck array. Have you defined it as part of the Deck object? Nope:
var loadedDeck = new Array(),
realDeck;
Change the declaration to this and it should work:
this.loadedDeck = []; // I'd use [] instead of new Array().
this.realDeck = [];
As #j08691 pointed out, you need to change realDeck to this.realDeck as well because you're calling it similarly here:
this.shuffle = function(){ //method
//creates the real deck
this.realDeck = this.loadedDeck;
//write shuffle function
};

You're referring to "loadedDeck" as if it's a property of your "Deck" object. It's not; it's just a local variable to the constructor closure.
Just call it "loadedDeck" and see if that helps. Same goes for "realDeck".
this.loadTheDeck = function(){ //method
for(var x=1;x<=13;x++){
loadedDeck.push(x+" Spades"); //<---issue line (all 4 are failing though this is the first)
loadedDeck.push(x+" Clubs");
loadedDeck.push(x+" Hearts");
loadedDeck.push(x+" Diamonds");
}
Also it'd be a good idea to get out of the habit of abusing document.write for debugging. Also don't forget to declare things like "x" with var!!

Your Deck object, which is accessed with this, has no "loadedDeck"-property. loadedDeck is a local variable. Just remove the "this.".

Related

Trying to simulate double buffering with javascript

I have a complex HTML element with huge numbers of divs inside. It is something like a calendar view. Now I want to refresh this view in the background e.g if some entries have changed on the server. For this, I started an EventSource which is asking the server if some data update has been done.
If so, I call the following function to load the new data
function calendarReplaceContent()
{
if(calendarDisplayFEList)
{
console.log("Start Replace");
loadJobs(false, calendarReplaceJobs, false); // load the new data
}
}
}
and if the loading is done this function is called
function calendarReplaceJobs()
{
console.log("Do Replace");
var oldContent = $('#calendarContentJobs'); // Get old Element
var calendarContentJob = oldContent.clone(); // Clone element
calendarContentJob.find('[id^="calendarjob_"]').remove(); // Remove old entries from cloned element
showJobs(false, calendarContentJob); // Draw new entries to cloned element
$('.rightTable').append(calendarContentJob); // Add new element to parent
oldContent.remove(); // Remove old element
}
This works fine, but each time the new element is added and the old one removed, this display is empty for a part of a second.
What I expected was that I will have now flickering on the display because I first append the new element (which in that case should be visible about the old one) and after that remove the old one.
Is there another way to replace the element with the new one without a flicker?
On further debugging I found out, that the find().remove is not working as expected. I thought this will only remove the children of the clone element. But in fact it also removes the elements starting with the id 'cleandarjob_' in the old existing element.
So how can I only remove all elements from the clone where the id ist starting with 'calendar job_'?
Double buffering in action
Here is how I do it on 2 canvas.
step1();
setTimeout(function () {
step2();
setTimeout(function () {
step3();
}, 1000);
}, 1000);
function step1() {
clearCanvas('myCanvas1');
drawShape('myCanvas1'
,{type:"circle", strokeStyle:"#000000", fillStyle:"#000000", radious:40, x:50, y:50});
};
function step2() {
clearCanvas('myCanvas2');
showOtherCanvas('myCanvas2', 'myCanvas1');
};
function step3() {
clearCanvas('myCanvas1');
drawShape('myCanvas1'
,{type:"circle", strokeStyle:"#000000", fillStyle:"#000000", radious:40, x:50, y:50});
showOtherCanvas('myCanvas1', 'myCanvas2');
};
function drawCircle (canvasID, info) {
var canvas = document.getElementById(canvasID);
var ctx = canvas.getContext('2d');
ctx.fillStyle=info.fillStyle;
ctx.strokeStyle=info.strokeStyle;
ctx.beginPath();
ctx.arc(info.x, info.y, info.radious, 0, 2 * Math.PI);
ctx.fill();
ctx.beginPath();
ctx.arc(info.x, info.y, info.radious, 0, 2 * Math.PI);
ctx.stroke();
}
function showOtherCanvas(cnv1, cnv2) {
var c1 = document.getElementById(cnv1);
var c2 = document.getElementById(cnv2);
c1.style['z-index'] = 3;
c2.style['z-index'] = 1;
c1.style['z-index'] = 2;
}
function clearCanvas(canvasID) {
var canvas = document.getElementById(canvasID);
var ctx = canvas.getContext('2d');
ctx.fillStyle="#FFFFFF";
ctx.strokeStyle="#FFFFFF";
ctx.fillRect(0,0,640,400);
}
function drawShape (canvasID, info) {
switch (info.type) {
case "circle" : drawCircle(canvasID, info);
}
}
<canvas id="myCanvas2" width="640" height="400"
style="border: 1px solid #000000; position: absolute; top: 10; left: 10; z-index:1">
</canvas>
<canvas id="myCanvas1" width="640" height="400"
style="border: 1px solid #000000; position: absolute; top: 10; left: 10; z-index:2">
</canvas>
The change is so fast you won't see any flicker.

Canvas Clear not working; Array items dont get deleted

The squares still get drawn even tough they are deleted from the array that is drawn. Shouldn't they be deleted when they are being deleted from the Array. Does the array not update inside the go function?
Javascript:
var canvas;
var ctx;
$(document).ready(function(){
$("#thebutton").on('click',function(){
thearray.pop();
})
canvas = $('#canvas').get(0);
ctx =canvas.getContext("2d");
})
class Square{
constructor(p1,p2,p3,p4){
this.p1=p1;
this.p2=p2;
this.p3=p3;
this.p4=p4;
}
start(){
var that = this;
setTimeout(function(){
that.go();
that.start();
console.log("timeout running");
},1000);
}
go(){
for(let i = 0; i<thearray.length;i++){
console.log("loop running:"+i);
if(true){
ctx.clearRect(0,0,500,500);
console.log("clearing rect");
}
ctx.rect(thearray[i].p1, thearray[i].p2, thearray[i].p3, thearray[i].p4);
ctx.stroke();
}
}
}
var thearray=[];
var thesquare1 = new Square(20,20,150,100);
var thesquare2 = new Square(100,100,200,200);
var thesquare3 = new Square(200,200,300,300);
thearray.push(thesquare1);
thearray.push(thesquare2);
thearray.push(thesquare3);
thesquare1.start();
HTML:
<canvas id="canvas" height="500" width="500"></canvas>
<button type="button" name="button" id="thebutton">Pop Array</button>
Spent almost an hour on debugging your code!
This led to the finding that if fillRect() is used instead of rect() the code works well...
and then finally found this..
(I too didn't know it before ><)
Have a look at this: link
In short, just call beginPath() after clearRect() to start a new path instead of using old path stack!!!
go(){
ctx.clearRect(0,0,500,500);
ctx.beginPath(); //This line saved the day :)))
console.log("clearing rect");
for(let i = 0; i<thearray.length;i++) {
console.log("loop running:"+i);
ctx.rect(thearray[i].p1, thearray[i].p2, thearray[i].p3, thearray[i].p4);
ctx.stroke();
}
}
using this the code works for rect() as intended :)
Note: also you have to move that clearRect() call outside the for loop otherwise it will clear the canvas after every single iteration of the loop which results in showing only the 3rd rectangle on the canvas.
Also, that if(true){} is not at all necessary.
Update: Also checkout this thread for some other alternatives to beginPath() to handle such scenario

How to optimize this Javascript code for a Paint App?

I'm working on a Paint App using Processing.js. Basically, when the mouse is dragged, mouseX and mouseY are saved in an array of objects called data[]. Afterwards the paint() function will run a loop that accesses every object of the data[] array and draws a line of color(data[i].R,data[i].G,data[i].B) and thickness data[i].T between the corresponding data[i].mouseX and data[i].mouseY coordinates. The problem is that the array keeps getting bigger the more you draw and in my case, when the length of the data[] array reaches ~800 elements it will start to lag, and keeps getting worse the more I keep drawing. Is there any tweak that will fix the lag or do I have to completely rethink the program?
<!DOCTYPE HTML>
<html>
<head>
<script src="https://github.com/downloads/processing-js/processing-js/processing-1.4.1.min.js"></script>
<script type="text/processing" data-processing-target="targetcanvas">
void setup() {
size(649, 600);
}
background(255,255,255);
var r=0;
var g=0;
var b=0;
var data = [];
var mousex;
var mousey;
var thickness=31;
var painting = false;
var counter=0;
var x;
var paint = function() {
background(255, 255, 255);
for(var i=1;i<data.length;i++){
if (data[i-1].mousex && data[i].mousex) {
strokeWeight(data[i].T);
stroke(data[i].R, data[i].G, data[i].B);
line(data[i].mousex,data[i].mousey,data[i-1].mousex,data[i-1].mousey);
fill(0,0,0);
text(data.length,10,10);
}
};
};
mouseDragged = function(){
painting = true;
data.push({mousex: mouseX, mousey: mouseY, R:r, G:g, B:b, T:thickness});
paint();
counter++;
};
mouseReleased = function() {
x=counter;
counter=0;
if(painting) {
data.push({mousex: 0, mousey: 0});
}
painting = false;
};
mouseOut = function() {
data.push({mousex: 0, mousey: 0});
}
</script>
<center>
<canvas id="targetcanvas"width="649" height="600" " style="border: 3px solid black; margin-top=100px;"></canvas>
</center>
</body>
</html>
Is this Processing.js or P5.js? Either way, the answer is the same.
You basically have a spectrum of options:
No data structures, no undo: Instead of storing your shapes and whatnot in data structures, just draw them directly to the canvas whenever the user does something. You can use a PGraphics canvas, or you can just draw directly to the screen, if you get rid of the call to background(). Then you don't need any data structures. The downside of this is you won't be able to remove shapes once they're drawn.
Some data structures, some undo: If you needed to be able to undo some of the shapes, but not all of them, you could do a mix of the above approach and your current approach. Instead of storing everything in data structures, you would only store the last 1-10 or so shapes. The rest of the shapes would be drawn directly to the PGraphics buffer.
Lots of data structure, lots of undo: If you really needed to be able to undo all of the shapes, then you could still use the PGraphics approach, but only redraw all of the shapes when something was removed.

Images on first load don't show on canvas

I want to pass a list of images and draw them each one for canvas.
My view.py:
def myview(request):
...
lista=Myobject.objects.filter(tipo=mytipo)
numero_oggetti = range(len(lista))
lista_formattata=[]
for elem in lista:
lista_formattata.append('/media/'+str(elem.myfield))
context_dict['lista']=lista_formattata
context_dict['numero_oggetti']=numero_oggetti
return render(request, 'mytemplate.html', context_dict)
My template.html:
<script>
<!--
window.onpageshow = function() {
myfunction({{lista|safe}});
};
-->
</script>
{% for c in numero_oggetti %}
<canvas id='componenti_canvas{{ c }}' width='60' height='75' style="border:1px solid #000000;">
Your browser does not support the HTML5 canvas tag.
</canvas>
{% endfor %}
My script.js:
function myfunction(lista) {
lista=lista
for (i=0; i<lista.length; i++) {
var canvas = document.getElementById('componenti_canvas'+i);
var ctx = canvas.getContext("2d");
var base = new Image();
base.src = lista[i];
ctx.scale(0.5,0.5);
ctx.drawImage(base, 0, 0);
};
};
This code works but sometimes the images show, sometimes don't (all of them or no one). When I load the page they don't show, when I re-load the page they show up. If I wait some minutes and re-load they don't show again.
I'm using firefox and in the console log when say GET image_name.png HTTP/1.0 200 they don't show (sometimes they are in cache, sometimes not... it don't make difference), when it don't say nothing they show.
I tried:
-setTimeout
-call the list with an ajax request with cache: false, async: false
-base.onload, like that:
base.onload = function(){
ctx.scale(0.5,0.5);
ctx.drawImage(base, 0, 0);
}
but or the images don't show never or they show in this way. I can give details, of course I can have done errors.
Edit: in the comment say to use onload.
My script.js:
function myfunction(lista) {
lista=lista
for (i=0; i<lista.length; i++) {
var canvas = document.getElementById('componenti_canvas'+i);
var ctx = canvas.getContext("2d");
var base = new Image();
base.onload = function() {
ctx.drawImage(base, 0, 0);
};
base.src = lista[i];
ctx.scale(0.5,0.5);
};
};
It draws only the last image on the last canvas (I have many canvas and I draw an image for each).
This will not work because you keep overwriting the image for every iteration of the loop. There is only one variable called base, it can only hold one image so all the ones before it are lost.
function myfunction(lista) {
lista=lista
for (i=0; i<lista.length; i++) {
var canvas = document.getElementById('componenti_canvas'+i);
var ctx = canvas.getContext("2d");
var base = new Image(); // second and more loops you over write base
base.onload = function() {
ctx.drawImage(base, 0, 0); // when it load only the last image is in base
// there is only one var called base so it
// can not hold more than one image
};
base.src = lista[i];
ctx.scale(0.5,0.5);
};
};
Use a function to wrap all the required vars so that you create a unique set for each image.
function myfunction(lista) {
lista.forEach((name,i)=>{ // each time the call back is called a
// new set of variables are created to
// store each unique image.
var base = new Image();
base.src = name;
base.onload = function() { ctx.drawImage(base, 0, 0); };
var canvas = document.getElementById('componenti_canvas'+i);
var ctx = canvas.getContext("2d");
ctx.scale(0.5,0.5);
});
}

Javascript create an image and make it move

I'm trying to make a little browser game where you can shoot bullets.
Right now I am able to make a bullet, but I don't know how to get in moving.
I have done this:
var bullet_id = 1;
var timer_id; // reference of the timer, needed to stop it
var speed = 350; // pixels/second
var period = 10; // milliseconds
var sprite; // the element that will move
var sprite_speed = 0; // move per period
var sprite_position = 315; // pixels
function createbullet() {
var img = document.createElement("img");
img.src = "images/bullet.png";
img.id = "bullet";
img.name = "bullet";
var foo = document.getElementById("fooBar");
foo.appendChild(img);
move(1);
bullet_id++;
}
function animate ()
{
document.getElementById("bullet").style.left=340 + "px";
sprite_position += sprite_speed;
sprite.style.left = sprite_position+'px';
}
function move(direction)
{
if (timer_id) stop();
sprite_speed = speed * period/1000 * direction;
timer_id = setInterval (animate, period);
}
function stop()
{
clearInterval (timer_id);
timer_id = null;
}
function init()
{
sprite = document.getElementById ("bullet"); // the HTML element we will move
animate(); // just to initialize sprite position
}
window.onload = init; // start doing things once the page has loaded */
I tried to add a bullet_id system but I couldn't get it working really.
Here is my html
<a onmousedown="document.jack.src=image2.src;" onmouseup="document.jack.src=image1.src;" onclick="createbullet()"><img id="jack" name="jack" src="/images/jack1.png" /></a>
<div id="fooBar"></div>
<script type="text/javascript" src="js/jquery.min.js"></script>
<script type="text/javascript">
document.getElementById('jack').addEventListener('click',function(){...})
Ok so maybe I didn't think that one through, have just designed one to see if I could and it works, hope it helps:
/********************************************************/
stg=0
bgx=0
spd=70
buls=0
act=false
/********************************************************/
function ani(){
var int
act=true
bgx-=52
stg++
$('#jack').css('background-position','-52px 0px')
int=setInterval(function(){
if(stg<4){bgx-=52; stg++}
else{ bgx=0; stg=0 }
$('#jack').css('background-position',bgx+'px 0px')
if(stg==4) new Bullet();
if(!stg){
act=false
clearInterval(int)
}
},spd)
}
/********************************************************/
function Bullet(){
var x,img,int
x=52
img=document.createElement('img')
img.src='bullet.png'
img.setAttribute('class','mh posAbs')
img.setAttribute('style','top:0px;left:'+x+'px')
img.setAttribute('id','bul'+buls)
scre.appendChild(img)
img=document.getElementById('bul'+buls)
buls++
int=setInterval(function(){
if(x<300){
x+=13
img.setAttribute('style','top:0px;left:'+x+'px')
}
else{
img.src='exp.png'
clearInterval(int)
setTimeout(function(){ scre.removeChild(img) },100)
}
},spd)
}
/********************************************************/
$(document).ready(function(){
$('html').keydown(function(){
if(!act){
if(event.keyCode==13) ani();
}
})
$('html').click(function(){
if(!act) ani();
})
})
/********************************************************/
<div id="scre" class="posRel">
<div id="jack"></div>
</div>
<style>
#jack{
width:52px;
height:37px;
background:url('02.png') no-repeat;
background-position:0px 0px;
background-size:auto 100%
}
</style>
Ok so what's happening above is every time you click or press Enter, the firing animation is called, which is animated in stages and when it gets to a certain stage it calls upon the Bullet() constructor to create a new Object or bullet.
While creating the bullet, the constructor generates an <img> and gives it a unique id based upon the buls variable, which is then incremented to keep the id's unique.
This is the most important part:
img=document.getElementById('bul'+buls)
It will NOT work without it as any references to img in the code after it will refer to the last img created and not say:- 'bullet 5 of 10 that are on screen'.
Once created the Bullet object handles the movement of the image it is referenced to, removing the need to move it with any other code...
P.S. The $('html').keydown(...) acts as an auto-fire!

Categories

Resources