I am trying to insert this JavaScript code (that is borrowed from someone else with credit given appropriately) into an HTML page. I understand how to use the simple document.write() to display text with JavaScript and am also pretty fluent in Java but am having a hard time trying to get these functions to work properly. For lack of a better word or words I am trying to get some animation to happen using JavaScript. I found various tutorials that show some JavaScript logic and print to the screen but none of them use animation and if they do show some animation they do not show how to include it into HTML. I want to display the animation properly within the HTML page. I have been reading through the w3 schools tutorials on JavaScript and most of them either return something or use the document.write to pull information from a form or a browser. I believe this might have something to do with creating an object to use for displaying the movement in the algorithm or with the DOM for JavaScript.
The idea behind my JavaScript is, I would like to simulate a working example of the bresenham line algorithm. There is an example of this here: Bresenham line algorithm
I also saw plenty of tutorials for including the JavaScript in a secondary file and referencing the JavaScript using the src tag but I would like to keep the JavaScript at the end of the html page please.
I am also using Dreamweaver for the development of the HTML & JavaScript page.
The code is listed below. Also please feel free to list a website or tutorial I can reference to view more information on this.
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Bresenham's Line Algorithm</title>
</head>
<body>
<script type="text/javascript">
/**
* Bresenham's line algorithm function
* by Matt Hackett [scriptnode.com]
* #param {Object} el The element to target (accepts both strings for id's and element *objects themselves)
* #param {Number} x1 The starting X coordinate
* #param {Number} y1 The starting Y coordinate
* #param {Number} x2 The finishing X coordinate
* #param {Number} y2 The finishing Y coordinate
* #param {Object} params Additional parameters [delay, onComplete, speed]
*/
var bresenham = function(el, x1, y1, x2, y2, params) {
var
interval,
b,
m,
sx,
y;
var init = function() {
var dx, dy, sy;
// Default parameters
params = params || {};
params.delay = params.delay || 10;
params.onComplete = params.onComplete || function(){};
params.speed = params.speed || 5;
// No point in doing anything if we're not actually moving
if ((x1 == x2) && (y1 == y2)) {
plot(x1, y);
params.onComplete();
return;
}
el = ((typeof el === 'string') ? document.getElementById(el) : el);
// Initalize the math
dx = x2 - x1;
sx = (dx < 0) ? -1 : 1;
dy = y2 - y1;
sy = (dy < 0) ? -1 : 1;
m = dy / dx;
b = y1 - (m * x1);
interval = setInterval(next, params.delay);
};
/**
* Execute the algorithm and move the element
*/
var next = function() {
y = Math.round((m * x1) + b);
plot(x1, y);
x1 += (sx * params.speed);
if (x1 >= x2) {
clearInterval(interval);
params.onComplete();
}
};
/**
* Move the target element to the given coordinates
* #param float x The horizontal coordinate
* #param float y The vertical coordinate
*/
var plot = function(x, y) {
el.style.left = x + 'px';
el.style.top = y + 'px';
};
init();
};
</script>
</body>
</html>
For me the code is fine. Maybe you just need elements to move in your page. According to the documentation of the function you need to specify the id of an element present in your page.
If you intend to run it at the startup of your page you will need to wait that the DOM of your page is constructed before doing any operation on the DOM. Else your function might try to access elements that are not yet constructed.
(There are several javascript frameworks that allows it cross browser)
Declare in the body the elements you want to be affected by your algorithm.
<div id="elt1" style="position:absolute; top : 200px; left : 200px">element1</div>
Then in chrome using the console I typed this and I got the animation working. I guess you shall declare the style of your element position:absolute because your algorithm uses top and left CSS properties that work with absolute positioned elements.
bresenham("elt1",100,100,300,300,null);
You've asked a very open question, so I'm at a loss how to answer it. I assume your page had some HTML on it that you've cut out to save space, but I think we probably need to see it (or at least some of it).
In general I can suggest that you avoid the w3 school website like the plague. Go here: http://w3fools.com for an explanation of why, and then scroll down to their What Can Be Done section for some good alternative references for JavaScript, HTML and CSS.
Avoid document.write() - especially don't try to use it to update your page after it has loaded, something I assume you'll need to do a lot if you're coding an animation, but in general you won't need document.write() at all. Google yourself a tutorial on document.getElementById() - a function that returns a reference to an HTML element on your page; you can use the returned reference to change that element's text, styles (and hence location), etc.
Don't worry about including the JavaScript in a separate file at this stage. There are good reasons for doing so in a real-world website, but if you are just experimenting and learning it's probably easier to keep everything in one page.
Take a look at http://htmldog.com/ and http://www.w3schools.com/ for basic introductions of how html, css and javascript interact. Also check out www.getfirebug.com for an intro to debugging JavaScript. Once you have this base understanding it becomes a lot easier to debug your programs and search for answers to questions you have.
A brief scan of the code shows that you are calling to an HTML element el via getElementById('el'); Unless you are writing the output directly to the document as you suggested using document.write() or alert() you have to have html to display the output of your code.
From a broader view what you want is first an understanding of how javascript and html interact, then you can start googling for tutorials to complete specific elements of whatever you are trying to build ie "how to display output using innerHTML()"...
Your problem is that although you loaded in the utilities to do something, you don't have any code that utilizes it.
For example:
function hello() {
alert('Hi!');
}
The code above should tell the user "hi", right?
Wrong.
The code to tell the user "hi" is there, but I never told it to, so it wouldn't.
Your page isn't doing anything because you need to give it instructions.
From looking through the code on that page, and the source for the animator, I can tell you this:
You need to add a call to brensenham and you need to give it details of what to do.
The details it needs are:
The element to animate
The beginning position
The finishing position
So what you need to add to the end of that script tag is:
// We need to make sure the elements are ready.
window.addEventListener('load', function () {
// Get the element and set up some details.
var element = document.getElementById('whatever-its-id-is'),
beginningX = 0,
beginningY = 0,
endX = 100,
endY = 100;
// Move the element.
brensenham(element, beginningX, beginningY, endX, endY);
});
Then change beginningX, beginningY, endX, and endY to whatever you actually want them to be.
I can tell that you're brand new to this whole thing, so I hope that was simple enough.
Related
I'm a beginner on here, so apologies in advance for naivety. I've made a simple image on Brackets using Javascript, trying to generate circles with random x and y values, and random colours. There are no issues showing when I open the browser console in Developer Tools, and when I save and refresh, it works. But I was expecting the refresh to happen on a loop through the draw function. Any clues as to where I've gone wrong?
Thanks so much
var r_x
var r_y
var r_width
var r_height
var x
var y
var z
function setup()
{
r_x = random()*500;
r_y = random()*500;
r_width = random()*200;
r_height = r_width;
x = random(1,255);
y= random(1,255);
z= random(1,255);
createCanvas(512,512);
background(255);
}
function draw()
{
ellipse(r_x, r_y, r_width, r_height);
fill(x, y, z);
}
Brackets.io is just your text editor (or IDE if you want to be technical) - so we can remove that from the equation. The next thing that baffles me is that something has to explicitly call your draw() method as well as the setup() method -
I'm thinking that you're working in some sort of library created to simplify working with the Canvas API because in the setup() method you're calling createCanvas(xcord,ycord) and that doesn't exist on it's own. If you want to rabbit hole on that task check out this medium article, it walks you thru all the requirements for creating a canvas element and then drawing on that canvas
Your also confirming that you're drawing at least 1 circle on browser refresh so i think all you need to focus on is 1)initiating your code on load and 2)a loop, and we'll just accept there is magic running in the background that will handle everything else.
At the bottom of the file you're working in add this:
// when the page loads call drawCircles(),
// i changed the name to be more descriptive and i'm passing in the number of circles i want to draw,
// the Boolean pertains to event bubbling
window.addEventListener("load", drawCircles(73), false);
In your drawCircles() method you're going to need to add the loop:
// im using a basic for loop that requires 3 things:
// initialization, condition, evaluation
// also adding a parameter that will let you determine how many circles you want to draw
function drawCircles(numCircles) {
for (let i = 0; i < numCircles; i++) {
ellipse(r_x, r_y, r_width, r_height);
fill(x, y, z);
}
}
here's a link to a codepen that i was tinkering with a while back that does a lot of the same things you are
I hope that helps - good luck on your new learning venture, it's well worth the climb!
Thank you so much for your help! What you say makes sense - I basically deleted the equivalent amount of code from a little training exercise downloaded through coursera, thinking that I could then essentially use it as an empty sandpit to play in. But there's clearly far more going on under the hood!
Thanks again!
Based on the matterjs demo I also created a set of bodies that live within an area. Just like in the demo the area is defined by four static bodies that together define a box.
When wildly moving bodies with the box they somehow seem to escape by going through the walls. Is there a way to prevent this escaping form happening? Maybe an alternative way to define the box?
This is actually a problem with all of these of collision detection algorithms.
What I ended up doing was adding code that knows about the box's boundaries and checks every 300 msecs if any of the bodies is outside of it. If so it uses Matter.Body.translate to put them back into the box again.
Notice that this code does not use the game loop but rather events for its check mechanism execution trigger. It would be nicer to do this using the matterjs game loop (run the retrieval every so many ticks), but I did not realise that at the time.
This is the code I ended up using (in my case the box is as big as the canvas itself):
/* `allBodies` is a variable that contains all the bodies that can
* escape. Use something like `Composite.allBodies(world)` to get
* them all but beware to not include the box's borders which are
* also bodies.
* `startCoordinates` is an object that contains the x and y
* coordinate of the place on the canvas where we should move escaped
* bodies to.
*/
function initEscapedBodiesRetrieval(allBodies, startCoordinates) {
function hasBodyEscaped(body) {
var x = body.position.x;
var y = body.position.y;
return x < 0 || x > _canvasWidth || y < 0 || y > _canvasHeight;
}
setInterval(function() {
var i, body;
for (i = 0; i < allBodies.length; i++) {
body = allBodies[i];
if (hasBodyEscaped(body)) {
Matter.Body.translate(body, { x: (startCoordinates.x - body.position.x), y: (startCoordinates.y - body.position.y) });
}
}
}, 300); /* We do this every 300 msecs */
}
I have a formula with several components, let's say w = x * y / z^2 + c. Now I have an input-field for each variable. My goal is, to calculate the missing one as soon, as all the others were entered. Difficulty is, that you can choose which fields you fill and which you want to leave free.
The easy (naive) way would of course be to resolve it for each variable by hand, detect the missing var, and have seperate js functions for each case. But I even have linked formulas (like x in the above formula is x = a + b, too) as well and the options are almost infinitive. Is there any option in JS to solve a formula by a specified variable? I could then replace each variable string with the assigned value and then eval the string.
First I thought Nerdamer would be the thing, but it turned out that it can only evaluate expressions and can't handle equations.
Is this possible? Any better idea?
Thanks in advance!
P.S.: My actual set of formula is:
dR = c * I^2 / A
R = L * dR
P = I * U
DV = R * I
DW = DV * I
It's for calculating losses in a cable due to ohm's resistance. Each Variable has a corresponding input field.
The following solution can be built for finding "R" using nerdamer. The logic can be extended to solve for the remaining variables. Do keep in mind that the current limitation is that nerdamer can currently only solve up to cubic functions algebraically. Higher order functions will be solved numerically.
//You can then take care of the non linear containing I. I is quadratic
var dR = nerdamer('R=L*dR').solveFor('dR');
var I = nerdamer('dR=c*I^2/A').sub('dR', dR).solveFor('I');
//You can first start by reducing the first few equations since they are linear and you can solve them as a linear system
var solutions = nerdamer.solveEquations(['P = I * U', 'DV = R * I', 'DW = DV * I'], ['I', 'DW', 'P']);
//the solutions come back as an array arrays in the form of [variable, value]
//you can see what they look like. In your case all your solutions will be in terns of DV & U since these are the only actual knowns
//You can see what the solutions look like
solutions.map(function(x) {
console.log('-'+x[0]+' = '+x[1]);
});
console.log('------------------ R ----------------');
var R = nerdamer.setEquation(I[0], solutions[0][1]).solveFor('R');
//I will have 3 solutions since it's cubic. You can console.log them below
R.map(function(x) {
console.log('R = '+x.toString());
});
<script src="https://cdn.jsdelivr.net/npm/nerdamer#latest/nerdamer.core.js"></script>
<script src="https://cdn.jsdelivr.net/npm/nerdamer#latest/Algebra.js"></script>
<script src="https://cdn.jsdelivr.net/npm/nerdamer#latest/Calculus.js"></script>
<script src="https://cdn.jsdelivr.net/npm/nerdamer#latest/Extra.js"></script>
<script src="https://cdn.jsdelivr.net/npm/nerdamer#latest/Solve.js"></script>
So I have an array (of length 1 for the moment) in Javascript. It contains an Image object for the moment. Basically, I made an animation that works perfectly with this code :
ants[0]._x = 5;
ants[0]._y = 5;
and then, in my updating function :
function animate() {
context.drawImage(ants[0], 0, 0, 158, 160, ants[0]._x, ants[0]._y, 158, 160);
ants[0]._x += 5;
ants[0]._y += 5;
}
The problem is, when I change _x and _y to x and y (like so :
ants[0].x = 5;
ants[0].y = 5;
and everywhere else in the code)
The animation won't work. Moreover, x and y equal to 0 even if I initialized them to 5.
So my question is, is it because my images are Images objects and to add new attributes to a built-in object, you have to add underscores ?
An Image object already has it's own readonly x and y properties. These correspond to the image width and height. Edit: actually corresponds to the position on the page If you're trying to set arbitrary values in your image, you need to create new variables. Previously you were doing this with the underscore character (_x), but you can do it with other characters too
For example:
ants[0].myProperty = 'stackoverflow';
console.log(ants[0].myProperty); // will print 'stackoverflow
You can view all the properties contained in an object with
var ants = new Image;
for (var p in ants) {
console.log(p);
}
MDN has more information on the Image element
There is nothing stopping you from assigning x and y under regular circumstances (ie: if you're using home-made objects, and not built-in language/browser objects).
When you start playing with reserved properties of protected objects, there are all kinds of weird things that can happen, from a browser letting you break the page completely until you refresh, or a browser letting you try for hours to change the definition of window.
It all comes down to how you assign them, how you use them after, whether you're swapping objects out of your array...
...and it's an Image object, so you need to make sure that the image is actually loaded before you can do much with it.
There's really nothing stopping you from doing things like:
var my_character = {
x : 0,
y : 0,
width : 32,
height : 64,
sprite_sheet : loadedImage,
current_frame : 6,
update : function () {
my_character.current_frame += 1;
my_character.x += 3;
my_character.y -= 2;
}
};
context.drawImage(
my_character.sprite_sheet,
x - my_character.width/2,
y - my_character.height/2,
my_character.width,
my_character.height,
my_character.width * current_frame,
0,
my_character.width,
my_character.height
);
That's not a particularly elegant way of doing it, but seriously, if you wanted to then add a my_character.$ = "35.99";, you could.
It's something more than "x" and "y".
If you wanted to use something like my_character.° = 32.5; I believe you'd have to use my_character["°"] = 32.5;
Yes, there's a convention, called Custom Data Attributes. Attributes that begin with data- are reserved for the application, they're guaranteed never to affect the semantics of the elements in the browser.
ant[0].setAttribute("data-x", 5);
ant[0].setAttribute("data-y", 5);
See the official W3C documentation and this blog post by John Resig summarizing it.
I am working on a server side physics experiment where the user controls an object through a socket. The problem I am running into results when the user moves the object outside the boundaries of the world.
I am using Box2Djs as installed through npm.
I create world 500x500 and then attach the following listener to it:
var boundaryListener = new b2d.b2BoundaryListener();
boundaryListener.Violation = function (body) {
//we will move this body to the opposite side
var position = body.GetWorldCenter();
//snap to opposite side
if (position.x < 0) {
position.x = worldAABB.upperBound.x + position.x;
}
if (position.y < 0) {
position.y = worldAABB.upperBound.y + position.y;
}
if (position.x > worldAABB.upperBound.x) {
position.x -= worldAABB.upperBound.x;
}
if (position.y > worldAABB.upperBound.y) {
position.y -= worldAABB.upperBound.y;
}
body.m_flags = body.m_flags & (~b2d.b2Body.e_frozenFlag); //does nothing :(
}
this.world.SetBoundaryListener(boundaryListener);
worldAABB is the b2AABB that the world uses as a boundary.
The problem is that I have noticed that when the boundary listener is fired, the flags are set to 22 which is allowSleep, frozen, and island flags. It would seem that when a b2Body passes outside the world boundary, it is frozen. That last line is an attempt to unfreeze the body by messing with the internal flags, but I have a distinct feeling that's the wrong way to do it.
How can I unfreeze the body? There are no functions that clear the frozen flags that I can see (the javascript is over 10,000 lines long so I honestly haven't read the whole thing) and placing some bodies as walls seems to have no effect (the user's object passes right through them).
My walls are created like so:
//create walls
var wallShape = new b2d.b2PolygonDef();
wallShape.SetAsBox(500, 10);
wallShape.density = 0.0;
wallShape.friction = 0.3;
var bodyDef = new b2d.b2BodyDef();
bodyDef.position.Set(250, 20);
var north = this.world.CreateBody(bodyDef);
north.CreateShape(wallShape);
bodyDef = new b2d.b2BodyDef();
bodyDef.position.Set(250, 499);
var south = this.world.CreateBody(bodyDef);
south.CreateShape(wallShape);
bodyDef = new b2d.b2BodyDef();
bodyDef.position.Set(499,250);
bodyDef.angle = Math.PI / 2;
var east = this.world.CreateBody(bodyDef);
east.CreateShape(wallShape);
bodyDef = new b2d.b2BodyDef();
bodyDef.position.Set(1, 250);
bodyDef.angle = Math.PI / 2;
var west = this.world.CreateBody(bodyDef);
west.CreateShape(wallShape);
Does anyone have any insights on how to fix this? There is very very little documentation I can find on using Box2D in javascript aside from the flash documentation that the website points to (which doesn't match half the time) and the C++ documentation which doesn't even talk about freezing.
It would probably be helpful to mention that the world has no gravity and all the objects have some linear and angular damping (its supposed to be a psuedo-in-space feel).
I had investigated Box2Djs source, and found next thing. Every time step Box2Djs checks if the body is inside the world boundaries. If body is out of range, then it "frozing", i.e. its excluding from collision detection. There this code (Body.js line 414):
Freeze: function(){
this.m_flags |= b2Body.e_frozenFlag;
this.m_linearVelocity.SetZero();
this.m_angularVelocity = 0.0;
for (var s = this.m_shapeList; s != null; s = s.m_next)
{
s.DestroyProxy();
}
}
Pay attention, this check performs every time step (b2Island.js 244). So, if you set e_frozenFlag at boundary listener, it will do nothing: flag will be set up at next time step. Thats more, after body had frozen, it losses its veolcity and its shapes looses theirs proxies in broad phase (as you can see from code above). Looks like proxies are not restroing automaticly, so, reseting flag is not enough.
I also not found somewhere in Box2Djs interface or logic for unfreezing bodies. Doing this manually is some kind of dirty trick, because you should acces BroadPhase, which is Box2Djs internal. Thats more, it dont help you, because on freezing body losses its velociy. But, as I see, you need continue body moving.
Solution is next. You should prevent body frozing at all in order to keep body in simulation after it moved out of world boundaries. It may be done by next trick. First, set world boundary with some large value. Then, set contact listener, and when body touches the walls, perform your boundary violation logic.
How to set contact listener in C++ you can see there: https://www.iforce2d.net/b2dtut/collision-callbacks Sory, I dont know java script and can't say, how to do this in Box2Djs.