Creating an object copies old - javascript

I have multiple canvas setup in my HTML page. I access them via their respective ID in JS/jQuery.
In this canvas there is a "player"-character (a basic square), that has a constant size and a variable position.
I create the player object like this:
<script>
var player = {
xpos = 50,
ypos = 50
}
</script>
in the same <script></script> I have a function that looks like this:
async animate(cid2){
var c = Object.create(player);
cid = $(cid2)[0];
ctx = cid.getContext("2d");
c.xpos = 50;
c.ypos = 50;
while(c.xpos < 300){
await sleep(1100);
c.xpos = c.xpos + 50;
//draw a rectangle..
}
Once any <canvas id="test"> is clicked, (with a jQuery .click Function), animate is executed with the respective canvas id.
All of this works great, as long as there is one canvas on the page.
If I have say two canvas, the following happens in the console:
canvas1 is clicked!
X-Position: 50
X-Position: 100
canvas2 is clicked!
X-Position: 150
X-Position: 200
Although the second canvas is clicked and a Object.create should create a new object, it doesn't work: It still accesses the old object.
I am almost certain there is an answer to this on SO, but despite my best efforts, I can't find it, because I don't know what is actually going wrong.
Can anyone help me or refer me to a question I could ask?
Thank you in advance.

You could use the (I think ECMAscript 6) spread operator
const obj = { myProp: 'hi' };
const newObj = { ...obj };
newObj.myProp = 'ciao';
console.log(obj); // still { myProp: 'hi' }
Know you should have two separate objects instead of a copy.

Related

How to see if PNG has a transparent background with Javascript [duplicate]

Is there a way to read transparent pixels from a picture using javascript?
I think, that it could be something similar to what PNG fixes does for IE (reading transparent pixels and applying some stuff, lol). But yes, for every browser..
Ah, would be awesome if it could be achieved without HTML5.
Well this question is actually answered by the dude from GoogleTechTalks in this video on javascript-based game engines.
http://www.youtube.com/watch?feature=player_detailpage&v=_RRnyChxijA#t=1610s
It should start at the point where it is explained.
Edit:
So I will summarize what is told in the video and provide a code-example.
It was a lot tougher than I had expected. The trick is to load your image onto a canvas and then check each pixel if it is transparent. The data is put into a two dimension array. Like alphaData[pixelRow][pixelCol]. A 0 is representing transparency while a 1 is not. When the alphaData array is completed it is put in global var a.
var a;
function alphaDataPNG(url, width, height) {
var start = false;
var context = null;
var c = document.createElement("canvas");
if(c.getContext) {
context = c.getContext("2d");
if(context.getImageData) {
start = true;
}
}
if(start) {
var alphaData = [];
var loadImage = new Image();
loadImage.style.position = "absolute";
loadImage.style.left = "-10000px";
document.body.appendChild(loadImage);
loadImage.onload = function() {
c.width = width;
c.height = height;
c.style.width = width + "px";
c.style.height = height + "px";
context.drawImage(this, 0, 0, width, height);
try {
try {
var imgDat = context.getImageData(0, 0, width, height);
} catch (e) {
netscape.security.PrivilegeManager.enablePrivilege("UniversalBrowserRead");
var imgDat = context.getImageData(0, 0, width, height);
}
} catch (e) {
throw new Error("unable to access image data: " + e);
}
var imgData = imgDat.data;
for(var i = 0, n = imgData.length; i < n; i += 4) {
var row = Math.floor((i / 4) / width);
var col = (i/4) - (row * width);
if(!alphaData[row]) alphaData[row] = [];
alphaData[row][col] = imgData[i+3] == 0 ? 0 : 1;
}
a=alphaData;
};
loadImage.src = url;
} else {
return false;
}
}
I got errors when running local in Firefox and the try catch statement solved it. Oh I gotta eat...
Edit 2:
So I finished my dinner, I'd like to add some sources I used and wich can be helpful.
https://developer.mozilla.org/En/HTML/Canvas/Pixel_manipulation_with_canvas
Info about the imageData object.
http://blog.nihilogic.dk/2008/05/compression-using-canvas-and-png.html
Even more info about the imageData object and it's use.
http://www.nihilogic.dk/labs/canvascompress/pngdata.js
A really helpful example of the use of imageData, the code I provided resembles this one for a big part.
http://www.youtube.com/watch?v=_RRnyChxijA
Infos on scripting game-engines in javascript, really really interesting.
http://blog.project-sierra.de/archives/1577
Infos about the use of enablePrivilege in firefox.
This is a bit tricky problem, since the only way to access files directly from Javascript is by using FileReader, which is a relatively new feature and not yet supported in most browsers.
However, you could get the desired result by using a canvas. If you have a canvas, you could assign it some distinctive color (such as neon green used in green screens). Then you could insert the image onto canvas and use the method mentioned here to get each individual pixel. Then you could check each pixel's color and see whether that point corresponds to your background color (ergo it's transparent) or does it have some other color (not transparent).
Kind of hackish, but don't think there's anything else you can do with pure JS.
It appears that GameJS can do this and much, much more. I am referencing this SO question for any/all of my knowledge, as I don't claim to actually have any about this topic.
Of course, this is HTML5, and uses the canvas element.

Argument 1 of CanvasRenderingContext2D.drawImage could not be converted ( attempting draw image on canvas object )

I am trying to make a cache of objects that can be used with canvas.drawImage() to display images but only draw them once. I keep getting this error, I have tried some answers found online like: canvasObject.get(0) and canvasObject[0] and unwrap(canvasObject) before putting them in the draw context, but none of that works. I cant find anything on it. hopefully someone can help. here is my code:
var canvas = full canvas that cached drawings should draw to
var temp = {};
var h = heightOfGridSquare;
var w = widthOfGridSquare;
var canvasElementForCache = document.createElement('canvas');
canvasElementForCache.width = w * 2; // so that i can draw pictures larger then single grid square
canvasElementForCache.height = h * 2;
var cachedCanvas = canvasElementForCache.getContext(ctx);
// cache drawing in app object
var cacheDrawing = function ( name ){
app.cache[name] = objectRepo[name](cachedCanvas);
};
var objectRepo = {
someObjectName: function (canv) {
var m = temp.coordinates;
canv.fillStyle = "rgba(0,0,200,0.9)";
canv.fillRect(m.x + 25, m.y + 25,50, 50); // random filler (x and y are coordinates defined in the draw object funciton )
return canv;
},
};
var drawObejectAtCoordinates = function ( x, y ) {
var px = ( x - ( w / 2 ));
var py = ( y + ( h / 2 ));
if ( app.cache[name] === undefined ){
temp.coordinates = { x:px, y:py };
cacheDrawing(name);
}
// drawing on actual canvas
canvas.drawImage( app.cache[name], px, py );
};
var render = function () {
drawObejectAtCoordinates( coordinateX, coordinateY );
// this is just a place holder, my actual code is very long and has different rendering methods..
// just know that it is being rendered ( not super important though since the error occurs at drawImage not render )
window.requestAnimationFrame(render);
}
this mostly exact, i have changed small parts for brevity.. but there is nothing left out that would be related to the issue im having. if anyone can help I would appreciate it greatly!
the error message is:
TypeError: Argument 1 of CanvasRenderingContext2D.drawImage could not be converted to any of: HTMLImageElement, HTMLCanvasElement, HTMLVideoElement.
and when I console log the contents of the cached canvas object it looks like this:
CanvasRenderingContext2D { canvas: <canvas>, globalAlpha: 1, globalCompositeOperation: "source-over", strokeStyle: "#41471d", fillStyle: "#ff8800", shadowOffsetX: 0, shadowOffsetY: 0, shadowBlur: 0, shadowColor: "rgba(0, 0, 0, 0)", mozCurrentTransform: Array[6] }
heres a jsFiddle example: https://jsfiddle.net/1krgqeq7/3/
There are a number of issues here that make this code rather difficult to follow:
1) You are reusing the variable cachedDrawing in a confusing way (is it an element or a function?)
2) You use a variable named temp which is usually a code smell, especially when you don't use it close to its declaration (not present in the code sample). Its also not clear why your stashing coords in there.
3) You use a fair number of descriptive variable names but in addition to temp you also use the rather non-descript 'obj'
But the answer to your question (related to 1 above) is that you are passing a context, not the canvas it was gotten from. Don't reassign that var and pass it into the cache instead.
Problems like this will likely be easier to spot with more descriptive variable names like cachedCanvas being a canvas and cachedCtx being its context.

In box2dweb how to destroy created body

I create bodies at mouse click with this pretty standard way in box2dweb:
*stage.onMouseDown = function(){
var fixDef = new box2d.b2FixtureDef;
fixDef.density = 1;
fixDef.friction = 0.5;
fixDef.restitution = 0.7;
var bodyDef = new box2d.b2BodyDef();
bodyDef.type = box2d.b2Body.b2_dynamicBody;
bodyDef.position.x = mouseX /scale;
bodyDef.position.y = mouseY /scale;
fixDef.shape = new box2d.b2CircleShape(Math.random()*100/scale);
world.CreateBody(bodyDef).CreateFixture(fixDef);}
I really don't know how to insert a name or an Id for my created bodies (eventually I can add a var num++ at every creation). Also, I don't know how to get back my body through the id and call the method .DestroyBody to delete it specifically.
I'm at early stages with JavaScript and Objective C so methods and docs made for Actionscript make me nuts..
Thanks in advance.
Question update:
I found a way to get back my already created object, finding the one i want among all of them using this way:
note: myBody is global
myBody['enter'+prodNum] = bodyDef;
bodyDef.userData = prodNum;
myBody['enter'+prodNum].id = bodyDef.userData;
prodNum is a global var which has a "++" at every cycle. With this i can recall my body back using both the body's var name and the bodyDef.userData property.
with the following function, called in my init() that's executed through window.onload, i can, as console.log shows, change what i want of my retrieved body, however no changes are applied to the body in canvas, even if its property in log resulted modified i cannot notice any change on the screen.
function reduceObj(){
var itsMe;
itsMe = myBody.enter10;
var newPosX = itsMe.position.x;
itsMe.active = false;
itsMe.awake = true;
itsMe.linearVelocity.x = 2000;
itsMe.position.x = newPosX+500;
itsMe.fixedRotation=true;
itsMe.allowSleep=true;
console.log(myBody.enter10,itsMe,itsMe.id,'it s me');
}
Cannot get why all this happens.. plus i already set the step() function which should refresh my world every x milliseconds... Help pls
The CreateBody function should return a reference you can keep, to destroy the body later.
var mybody = CreateBody( bodyDef );
mybody.CreateFixture( fixDef );
You can't just set properties in a body to change it, you need to use the appropriate functions:
// later...
mybody.SetActive( false );
mybody.SetAwake( true );
var vel = mybody.GetLinearVelocity();
vel.x = 2000;
mybody.SetLinearVelocity( vel );
var pos = mybody.GetPosition();
pos.x += 500;
mybody.SetPosition( pos );
mybody.SetFixedRotation( true );
mybody.SetSleepingAllowed( true );
Please keep in mind that 500 units is half a kilometer, so that's probably not what you would want to be doing. Use meters for your dimensions, not pixels. A velocity of 2000m/s is around 7200km/h or mach 6 (as reference the fastest aircraft ever built does about mach 8, so this is also most likely not what you want). Take a look at this page for some other common gotchas: http://www.iforce2d.net/b2dtut/gotchas

draw preloaded image into canvas

Once again, completely out of my depth but I need to preload some images and then add them to the page when 'all elements (including xml files etc.)' are loaded. The images and references are stored in an array for later access. Trying to draw and image from that array throws an error yet I know it is available as I can just appendTo the page:
preloadImages: function (loadList, callback) {
var img;
var loadedFiles = [];
var remaining = loadList.length;
$(loadList).each(function(index, address ) {
img = new Image();
img.onload = function() {
--remaining;
if (remaining <= 0) {
callback(loadedFiles);
}
};
img.src = loadList[index];
loadedFiles.push({file: 'name of image to be loaded', image: img }); //Store the image name for later refernce and the image
});
}
//WHEN CERTAIN OTHER CONDITIONS EXIST I CALL THE FUNCTION BELOW
buildScreen: function ( imageLocs, image){
//THIS FUNCTION LOOPS THROUGH imageLocs (XML) AND CREATES CANVAS ELEMENTS, ADDING CLASSES ETC AND DRAWS PART OF A SPRITE (image)
//INTO THE CANVASES CREATED
var ctx = $('ID of CANVAS').get(0).getContext("2d");
var x = 'position x in imageLocs'
var y = 'position y in imageLocs'
var w = 'width in imageLocs'
var h = 'position x in imageLocs'
ctx.drawImage(image, x,y, w, h, 0, 0, w, h); //THIS THROWS AN ERROR 'TypeError: Value could not be converted to any of: HTMLImageElement, HTMLCanvasElement, HTMLVideoElement'
//$(image).appendTo("#innerWrapper") //YET I KNOW THAT IT IS AVAILABE AS THIS LINE ADDS THE IMAGE TO THE PAGE
}
Problem
The issue is caused because you are passing a jQuery object to a native function, in this case ctx.drawImage, drawImage will only support native objects.
startSequence : function(){
$('#innerWrapper').empty();
var screenImageRef = $.grep(ST.imageFilesLoaded, function(e){
return e.file == 'AtlasSheet'
});
var screenImage = $(screenImageRef[0].image);
var imageLocsRef = $.grep(ST.xmlFilesLoaded, function(e){
return e.file == 'IMAGELOCS'
});
var imageLocs = $(imageLocsRef[0].xml);
//$(screenImage).appendTo("#innerWrapper") //appends screenImage
Utilis.buildScreen('1', imageLocs, screenImage, ST.didYouSeeIt, 'ST')
}
Your screenImage var is created by $(screenImageRef[0].image), this will return a jQuery object that wrappers the native image object. To get back to the original native image object use the following:
screenImage.get(0)
or
screenImage[0]
The former is the jQuery supported way.
Solution
So the fix to your code should be either, changing the following line:
Utilis.buildScreen('1', imageLocs, screenImage.get(0), ST.didYouSeeIt, 'ST');
Or changing the line in the buildScreen method:
ctx.drawImage(image.get(0), x,y, w, h, 0, 0, w, h);
... Whichever you prefer.
Confusion when debugging
The reason why everything appears to work when you append the image, is because you are using jQuery to append the image, and jQuery supports being passed jQuery wrapped elements. If you had tried to append your screenImage using native functions i.e. Element.appendChild() you would have got similar errors.
Just to help in future, it's always best to use console.log to find out what type/structure a variable actually has. Using console.log on your previous image var would have given a strange object dump of the jQuery wrapper (which might have rang alarm bells), rather than the expected [object HTMLImageElement] or some other image/console related output (depending on the browser).
I think your image preloader isn't quite correct as it uses the same img variable for all images.
Here is one that I know works well: https://gist.github.com/eikes/3925183

Image appearing multiple times on canvas?

I'm drawing a simple dynamic canvas and I'm wondering how I can make the .png file in my drawImage method appear like 40 times at different places on my canvas at the same time?
Thanks beforehand! :)
Thank you all very much for your reply! This is as far as I've gotten now:
<script type="text/javascript">
var ctx;
var imgBg;
var imgDrops;
var x = 40;
var y = 0;
function setup() {
var canvas = document.getElementById('canvasRegn');
if (canvas.getContext) {
ctx = canvas.getContext('2d');
setInterval('draw();', 36);
imgBg = new Image();
imgBg.src = 'dimma.jpg';
imgDrops = new Image();
imgDrops.src = 'drop.png';
}
}
function draw() {
drawBackground();
for(var i=0; i <= 40; i++) {
ctx.drawImage (imgDrops, x, y);
y += 3;
if(y > 450)
y = -20;
x=Math.random()*600;
}
}
function drawBackground(){
ctx.drawImage(imgBg, 0, 0);
}
</script>
My problem is now that the images are jumping all over the place... I want them "falling" down slowly from above and coming back around:(
Have a look at this fiddle http://jsfiddle.net/joevallender/D83uC/10/
I made it to explain some basics of canvas to a friend recently. Although I'm using shapes instead of .png files I think the loop you are looking for is the same.
The key bit of code being this loop below
setInterval(function(){
// clear stage
context.clearRect(0, 0, width, height);
for(var i = 0; i < balls.length; i++) {
balls[i].move(balls);
}
}, 1000/FPS)
FPS is a variable, and .move() is a function that calculated new co-ordinates for and then re-draws the ball object.
I think it might simply not clearing the 'stage' context.clearRect(0, 0, width, height);
EDIT Perhaps that example had too much going on in it to be useful.
Please see a much earlier version http://jsfiddle.net/joevallender/D83uC/2 that simple animates the ball. The main point remains though, you need to clear the canvas if you don't want the 'trails'
Think of canvas like windows paint, not flash. The things you have drawn aren't editable objects. You need to redraw the whole thing each time. (Unless you use a JS library that makes things seem more like flash - but I'm guessing you want to learn without helper libraries at first)
As I said, I was explaining canvas to someone recently and you can see the various stages between the two links I've sent you by changing the number on the end of the URL http://jsfiddle.net/joevallender/D83uC/3
http://jsfiddle.net/joevallender/D83uC/4
etc.
EDIT2
Or if I've misunderstood, post a jsfiddle and let us know what is wrong with it
This is what you need: http://edumax.org.ro/extra/new/imagetut/
You can get the code here: http://edumax.org.ro/extra/new/imagetut/script.js
The relevant part is this:
function draw_image(){
//draw one image code
}
window.onload = function () {
for (var i=0;i<10;i++){
for (var j=0;j<10;j++){
draw_image(10+i*40, 10+j*40, 40, 40);
}
}
}
This code only explains the concept, it will not work by itself, for a full version check the link above.

Categories