Replicating child elements in JavaScript [Bug] - javascript

I am trying to solve a problem for an assignment, where the objective is to build a game. The game loads with smiley faces shown across two columns(divs) laid out side by side. There is one extra smiley on the left div, and if the user clicks on that extra smiley, the next run of the game should:
Increase the number of smileys by 5, for the next run
Generate a whole new set of smileys for the second run(by removing existing smileys from the current run).
The code I have so far has a bug. If I include the code for removing child nodes from the current run of the game, in the next run 5 more smileys are not added. If I remove this code, then in the next run, 5 more smileys are added but the previous smileys are at the same position (meaning they are not removed).
Here's the JS code:
var numberOfFaces = 5;
var theLeftSide = document.getElementById("leftSide");
var theRightSide = document.getElementById("rightSide");
var theBody = document.getElementsByTagName("body")[0];
function generateFaces() {
//remove current children
while(theLeftSide.firstChild){
theLeftSide.removeChild(theLeftSide.firstChild);
}
while(theRightSide.firstChild){
theRightSide.removeChild(theRightSide.firstChild);
}
while(numberOfFaces > 0) {
var face = document.createElement("img");
face.src = "http://home.cse.ust.hk/~rossiter/mooc/matching_game/smile.png";
var topValue = generateRandomNumber(0,400);
face.style.top = topValue+"px";
var leftValue = generateRandomNumber(0,400);
face.style.left = leftValue+"px";
theLeftSide.appendChild(face);
//changes
var leftSideImages = theLeftSide.cloneNode(true);
var leftSideLastImage = leftSideImages.lastChild;
leftSideImages.removeChild(leftSideLastImage);
theRightSide.appendChild(leftSideImages);
//4th - generate 5 more faces for correct click in left side
theLeftSide.lastChild.onclick = function nextLevel(event){
event.stopPropagation();
numberOfFaces += 5;
generateFaces();
};
theBody.onclick = function gameOver() {
alert("Game Over!");
theBody.onclick = null;
theLeftSide.lastChild.onclick = null;
};
numberOfFaces--;
}
}
function generateRandomNumber(min, max) {
return Math.floor(Math.random() * (max-min + 1));
}
And this is the link to the Fiddle.
I also made a Codepen pen that has the same code.
Would appreciate any help.
Update -
My function structure was somewhat different in earlier attempts. I revised it based on some forum comments. Here's the earlier structure-
function generateFaces() {
//remove current children
while(theLeftSide.firstChild){
theLeftSide.removeChild(theLeftSide.firstChild);
}
while(theRightSide.firstChild){
theRightSide.removeChild(theRightSide.firstChild);
}
while(numberOfFaces > 0) {
var face = document.createElement("img");
face.src = "http://home.cse.ust.hk/~rossiter/mooc/matching_game/smile.png";
var topValue = generateRandomNumber(0,400);
face.style.top = topValue+"px";
var leftValue = generateRandomNumber(0,400);
face.style.left = leftValue+"px";
theLeftSide.appendChild(face);
numberOfFaces--;
}
//changes
var leftSideImages = theLeftSide.cloneNode(true);
var leftSideLastImage = leftSideImages.lastChild;
leftSideImages.removeChild(leftSideLastImage);
theRightSide.appendChild(leftSideImages);
//4th - generate 5 more faces for correct click in left side
theLeftSide.lastChild.onclick = function nextLevel(event){
event.stopPropagation();
numberOfFaces += 5;
generateFaces();
};
theBody.onclick = function gameOver() {
alert("Game Over!");
theBody.onclick = null;
theLeftSide.lastChild.onclick = null;
};
//numberOfFaces--;
}

You are decrementing numberOfFaces to zero in the while loop and add 5 again, so the value is always 5.
Change the while loop to
for(var n = 0; n < numberOfFaces; n++) {
var face = document.createElement("img");
face.src = "http://home.cse.ust.hk/~rossiter/mooc/matching_game/smile.png";
var topValue = generateRandomNumber(0,400);
face.style.top = topValue+"px";
var leftValue = generateRandomNumber(0,400);
face.style.left = leftValue+"px";
theLeftSide.appendChild(face);
...
}
and each run adds an extra 5 smiley set. Altered fiddle here

Append your right child after while loop:
var numberOfFaces = 5;
var theLeftSide = document.getElementById("leftSide");
var theRightSide = document.getElementById("rightSide");
var theBody = document.getElementsByTagName("body")[0];
function generateFaces() {
//remove current children
while(theLeftSide.firstChild){
theLeftSide.removeChild(theLeftSide.firstChild);
}
while(theRightSide.firstChild){
theRightSide.removeChild(theRightSide.firstChild);
}
while(numberOfFaces > 0) {
var face = document.createElement("img");
face.setAttribute("src", "http://home.cse.ust.hk/~rossiter/mooc/matching_game/smile.png");
//face.src = "http://home.cse.ust.hk/~rossiter/mooc/matching_game/smile.png";
var topValue = generateRandomNumber(0,400);
face.style.top = topValue+"px";
var leftValue = generateRandomNumber(0,400);
face.style.left = leftValue+"px";
theLeftSide.appendChild(face);
//changes
var leftSideImages = theLeftSide.cloneNode(true);
var leftSideLastImage = leftSideImages.lastChild;
leftSideImages.removeChild(leftSideLastImage);
//4th - generate 5 more faces for correct click in left side
theLeftSide.lastChild.onclick = function nextLevel(event){
event.stopPropagation();
numberOfFaces += 5;
generateFaces();
};
theBody.onclick = function gameOver() {
alert("Game Over!");
theBody.onclick = null;
theLeftSide.lastChild.onclick = null;
};
numberOfFaces--;
}
theRightSide.appendChild(leftSideImages);
}
function generateRandomNumber(min, max) {
return Math.floor(Math.random() * (max-min + 1));
}
Check out codepen

Related

Reset values Issue

Building a dice game and you get 3 rolls. Once you finish your turn i'm trying to have a "reset" button that will reset the values back to the original spot so the "next person" can play. The values reset as I expected but when I "roll" none of the functions are taking place and i'm pretty new in js so i'm not sure what the problem is.
var playerScore = document.getElementById('firstPlayerScore');
var rollButton = document.getElementById('roll_button');
var dice1 = new dice(1);
var dice2 = new dice(2);
var dice3 = new dice(3);
var dice4 = new dice(4);
var dice5 = new dice(5);
var diceArray = [dice1, dice2, dice3, dice4, dice5];
var cargo = 0;
var numOfRolls = 0;
var cargoButton = document.getElementById('cargo');
var canHaveCargo = false;
function restart(){
dice1 = new dice(1);
dice2 = new dice(2);
dice3 = new dice(3);
dice4 = new dice(4);
dice5 = new dice(5);
diceArray = [dice1, dice2, dice3, dice4, dice5];
cargo = 0;
numOfRolls = 0;
canHaveCargo = false;
addGlow();
updateDiceImageUrl();
document.getElementById("dice1").classList.remove('glowing');
document.getElementById("dice2").classList.remove('glowing');
document.getElementById("dice3").classList.remove('glowing');
document.getElementById("dice4").classList.remove('glowing');
document.getElementById("dice5").classList.remove('glowing');
}
//dice object
function dice(id){
this.id = id;
this.currentRoll = 1;
this.previousRoll = 1;
this.isSelected = false;
this.diceImageUrl = "img/dice/dice1.png";
this.roll = function(){
this.previousRoll = this.currentRoll;
this.currentRoll = getRandomRoll(1, 6);
}
}
//returns an array of all dice that are not currently selected so they can be rolled.
function getRollableDiceList(){
var tempDiceList = [];
for(var i = 0; i < diceArray.length; i++){
if(!diceArray[i].isSelected){
tempDiceList.push(diceArray[i]);
}
}
return tempDiceList;
}
// gets a random number between min and max (including min and max)
function getRandomRoll(min,max){
return Math.floor(Math.random() * (max-min + 1) + min);
}
// calls the roll function on each dice
function rollDice(rollableDiceList){
for(var i = 0; i < rollableDiceList.length; i++){
rollableDiceList[i].roll();
}
}
// updates each dice with the new url for the image that corresponds to what their current roll is
function updateDiceImageUrl(){
for(var i = 0; i < diceArray.length; i++){
var currentDice = diceArray[i];
currentDice.diceImageUrl = "http://boomersplayground.com/img/dice/dice" + currentDice.currentRoll + ".png";
//update div image with img that cooresponds to their current roll
updateDiceDivImage(currentDice);
}
}
//Displays the image that matches the roll on each dice
function updateDiceDivImage(currentDice) {
document.getElementById("dice"+currentDice.id).style.backgroundImage = "url('" + currentDice.diceImageUrl +"')";
}
// returns an array of all
function getNonSelectedDice(){
var tempArray = [];
for(var i = 0; i < diceArray.length; i++){
if(!diceArray[i].isSelected){
tempArray.push(diceArray[i]);
}
tempArray.sort(function(a, b){
return b.currentRoll - a.currentRoll;
});
}
return tempArray;
}
function getSelectedDice(){
var selectedDice = [];
for(var i = 0; i < diceArray.length; i++){
if(diceArray[i].isSelected){
selectedDice.push(diceArray[i]);
}
}
return selectedDice;
}
//boolean variables
var shipExist = false;
var captExist = false;
var crewExist = false;
//checks each dice for ship captain and crew. Auto select the first 6, 5 , 4.
function checkForShipCaptCrew(){
//array of dice that are not marked selected
var nonSelectedDice = getNonSelectedDice();
for(var i = 0; i < nonSelectedDice.length; i++){
//temp variable that represents the current dice in the list
currentDice = nonSelectedDice[i];
if (!shipExist) {
if (currentDice.currentRoll == 6) {
shipExist = true;
currentDice.isSelected = true;
}
}
if (shipExist && !captExist) {
if (currentDice.currentRoll == 5) {
captExist = true;
currentDice.isSelected = true;
}
}
if (shipExist && captExist && !crewExist) {
if (currentDice.currentRoll == 4) {
crewExist = true;
currentDice.isSelected = true;
canHaveCargo = true;
}
}
}
}
function addGlow(){
var selectedDice = getSelectedDice();
for (var i = 0; i < selectedDice.length; i++){
var addGlowDice = selectedDice[i];
var element = document.getElementById('dice' + addGlowDice.id);
element.className = element.className + " glowing";
}
}
function getCargo(){
var cargo = 0;
var moreDice = getNonSelectedDice();
if (canHaveCargo){
for(var i=0; i < moreDice.length; i++){
cargo += moreDice[i].currentRoll;
playerScore.innerHTML = 'You have got ' + cargo + ' in ' + numOfRolls + ' rolls!';
}
} else {
alert("You don't have Ship Captain and the Crew yet!");
}
}
rollButton.addEventListener('click', function(){
//generate rollable dice list
if (numOfRolls < 3) {
var rollableDiceList = getRollableDiceList();
//roll each dice
rollDice(rollableDiceList);
//update dice images
updateDiceImageUrl();
getNonSelectedDice();
// //auto select first 6, 5, 4 (in that order)
checkForShipCaptCrew();
addGlow();
// //adds a red glow to each dice that is selected
numOfRolls++;
}
});
cargoButton.addEventListener('click', getCargo);
var startButton = document.getElementById('restart');
startButton.addEventListener('click', restart);
http://boomer1204.github.io/shipCaptainCrew/
Here is a link to the live game since it's the only way I can describe the problem since I don't know what's not working. If you roll the dice a couple times the dice will get a blue border and be "saved" according to the rules. Now after you hit th restart button that doesn't happen anymore.
Thanks for the help in advance guys
Just add this to your restart()
function restart(){
...
shipExist = false;
capExist = false;
crewExist = false;
...
}
It's hard to replicate without a fiddle, but it seems that you are adding and removing the 'glowing' class using separate processes. Have you tried adding the glowing class the same way you are removing it?
element.classList.add("glowing")
See an example within a fiddle: https://jsfiddle.net/5tstf2f8/

jQuery addClass or other methods doesn't seem to works on an element

(Sorry for my bad english)
I know, this question has been posted so many times, but the threads that I read didn't fix my problem.
I have a grid, with a random black cell drawn for each time I refresh the page. When the time come to "00:01", the cell need to replicate with the neighbors cells, I tried to put a background-color with jQuery, I tried to use attr('id', 'replicant'), I tried addClass... Nothing seem to work :S
Here the code for the draw :
function drawReplicant(replicant, cellTab)
{
for (var i = 0; i < replicant.length; i++) {
if($.inArray(replicant[i], cellTab))
{
var concat = 'row'+replicant[i].x+'col'+replicant[i].y;
$(concat.toString()).addClass("replicant");
}
}
}
And here, the full code :
var lastClicked;
var cellTab = Array();
var replicant = Array();
var neightbors = Array();
var newReplicant = Array();
var randomRow = Math.floor((Math.random() * 10) + 1);
var randomCol = Math.floor((Math.random() * 10) + 1);
var rows = 10;
var cols = 10;
var grid = clickableGrid(rows, cols,randomRow,randomCol,cellTab, function(el,row,col,i){
console.log("You clicked on element:",el);
console.log("You clicked on row:",row);
console.log("You clicked on col:",col);
console.log("You clicked on item #:",i);
$(el).addClass('clicked');
lastClicked = el;
});
document.getElementById("game").appendChild(grid);
function clickableGrid( rows, cols, randomRow, randomCol, cellTab, callback ){
var i=0;
var grid = document.createElement('table');
grid.className = 'grid';
for (var r=0;r<rows;++r){
var tr = grid.appendChild(document.createElement('tr'));
for (var c=0;c<cols;++c){
var cell = tr.appendChild(document.createElement('td'));
$(cell).addClass('row'+r+'col'+c);
if(randomCol == c && randomRow == r)
{
storeCoordinate(r, c, replicant);
$(cell).css('background', '#000000');
}
storeCoordinate(r, c, cellTab);
cell.addEventListener('click',(function(el,r,c,i){
return function(){
callback(el,r,c,i);
}
})(cell,r,c,i),false);
}
}
return grid;
}
function storeCoordinate(xVal, yVal, array)
{
array.push({x: xVal, y: yVal});
}
function replicate(replicant)
{
for (var i = 0; i < replicant.length; i++) {
var supRowX = replicant[i].x-1;
var supRowY = replicant[i].y;
storeCoordinate(supRowX, supRowY, newReplicant);
var subRowX = replicant[i].x+1;
var subRowY = replicant[i].y;
storeCoordinate(subRowX, subRowY, newReplicant);
var supColsX = replicant[i].x;
var supColsY = replicant[i].y-1;
storeCoordinate(supColsX, supColsY, newReplicant);
var subColsX = replicant[i].x;
var subColsY = replicant[i].y+1;
storeCoordinate(subColsX, subColsY, newReplicant);
}
}
function drawReplicant(replicant, cellTab)
{
for (var i = 0; i < replicant.length; i++) {
if($.inArray(replicant[i], cellTab))
{
var concat = 'row'+replicant[i].x+'col'+replicant[i].y;
$(concat.toString()).addClass("replicant");
}
}
}
var w = null; // initialize variable
// function to start the timer
function startTimer()
{
// First check whether Web Workers are supported
if (typeof(Worker)!=="undefined"){
// Check whether Web Worker has been created. If not, create a new Web Worker based on the Javascript file simple-timer.js
if (w==null){
w = new Worker("w.countdown.js");
}
// Update timer div with output from Web Worker
w.onmessage = function (event) {
var bool = false;
document.getElementById("timer").innerHTML = event.data;
if(event.data == "00:01")
{
replicate(replicant);
replicant = newReplicant;
drawReplicant(replicant, cellTab);
}
};
} else {
// Web workers are not supported by your browser
document.getElementById("timer").innerHTML = "Sorry, your browser does not support Web Workers ...";
}
}
// function to stop the timer
function stopTimer()
{
w.terminate();
timerStart = true;
w = null;
}
startTimer();
The replication WORKS, I have my new replicants in my array. But when I loop in this array to draw them, it doesn't seem to work although I'm able to get the cell to draw with :
var concat = 'row'+replicant[i].x+'col'+replicant[i].y;
If my first black cell if at the row4col4 position, this line will return :
row3col4
row5col4
row4col3
row4col5
And then, when the timer will restart, those 5 black cells will replicate with their neighbors, etc.
I use a web worker for the timer, here the code :
var timerStart = true;
function myTimer(d0)
{
// get current time
var d=(new Date()).valueOf();
// calculate time difference between now and initial time
var diff = d-d0;
// calculate number of minutes
var minutes = Math.floor(diff/1000/60);
// calculate number of seconds
var seconds = Math.floor(diff/1000)-minutes*60;
var myVar = null;
// if number of minutes less than 10, add a leading "0"
minutes = minutes.toString();
if (minutes.length == 1){
minutes = "0"+minutes;
}
// if number of seconds less than 10, add a leading "0"
seconds = seconds.toString();
if (seconds.length == 1){
seconds = "0"+seconds;
}
if(seconds >= 20)
{
seconds = "00";
}
// return output to Web Worker
postMessage(minutes+":"+seconds);
}
if (timerStart){
// get current time
var d0=(new Date()).valueOf();
// repeat myTimer(d0) every 100 ms
myVar=setInterval(function(){myTimer(d0)},1000);
// timer should not start anymore since it has been started
timerStart = false;
}
Thanks a lot :-)

jquery fadeIn and fade out dynamic content

I have a function that loads data into divs and after a set time fades that data out. I cant figure a way to replace the data then fade it back again.
setInterval(function(){
for(var a = 0; a < amount; a++){
var tempStore = $('#adCam_'+a).html();
$('#adCam_'+a).children().fadeOut(500,function(){
$('#adCam_'+a).html(storedAds[a]);
$('#adCam_'+a).children().fadeIn(500);
});
storedAds[a] = tempStore;
}
},2000);
I had this working by just switching the data which worked perfectly:
setInterval(function(){
for(var a = 0; a < amount; a++){
var tempStore = $('#adCam_'+a).html();
$('#adCam_'+a).html(storedAds[a]);
storedAds[a] = tempStore;
}
},60000);
But animating them out would look nicer for the user. Is there a way to animate the content back in after it has been switched?
There is few things. The data to be switched is stored and replaced in array each time.
And the data is brought from an ajax request.
Full Source Code:
var adAlign = 'left';
var storedAds = Array();
var currentAd = 0;
function setAds(user_data,ad_id){
var dh = window.innerHeight - 130;
var adH = 170;
var amount = dh/adH;
var space = dh - adH;
var amount = String(dh/adH);
var dec = amount.split(".");
amount = parseInt(dec[0]);
var margin = parseInt(space)/parseInt(amount);
$.ajax({
url:'global.func/pc_ad_campaign.php?'+ad_id+'=true',
type:'POST',
dataType:"JSON",
data:{
amount:amount,
margin:margin,
gender:user_data['gender'],
age:user_data['age'],
sport:user_data['sport'],
interests:user_data['interests']
},
success:function(json){
if(json.err > 0){
}else{
var m = margin / 4;
$('.ad').css('margin-top',m+'px');
for(var x = 0; x < amount; x++){
$('#ads').html($('#ads').html() + '<div id="adCam_'+x+'" class="ad ad_'+adAlign+'" style="margin-top:'+m+'px">'+json.data[x]+'</div>');
storedAds.push(json.data[parseInt(x + amount)]);
if(adAlign === 'left'){
adAlign = 'right';
}else{
adAlign = 'left';
}
}
setInterval(function(){
for(var a = 0; a < amount; a++){
var tempStore = $('#adCam_'+a).html();
$('#adCam_'+a).html(storedAds[a]);
storedAds[a] = tempStore;
}
},60000);
}
}
});
}
Data returned: (just testing at the moment)
die(json_encode(array('err' => 0, 'data' => array('<div>ad 1</div>','<div>ad 2</div>','<div>ad 3</div>','<div>ad 4</div>', '<div>ad 5</div>', '<div>ad 6</div>'))));
Image visual: (in case it helps)
Two things :
First :
$('#adCam_'+a).html(storedAds[a]);
$('#adCam_'+a).children().fadeIn(500);
You replace the faded out content with a new content, this one has not been faded out, so fadeIn will do nothing. You should do something like:
$e = $(storedAds[a]).css({'display':'none', 'opacity', 0});
$('#adCam_'+a).children().remove();
$('#adCam_'+a).append($e);
$('#adCam_'+a).children().fadeIn(500);
Then :
var tempStore = $('#adCam_'+a).html();
$('#adCam_'+a).children().fadeOut(500,function(){
$('#adCam_'+a).html(storedAds[a]);
...
});
storedAds[a] = tempStore;
Here you actually do storedAds[a] = tempStore; before the fadeOut callback so this line $('#adCam_'+a).html(storedAds[a]); may just add tempStore into your container ... that's not what you want right ?
Hope this helps.

assign parameter value of an object javascript

I have been looking at this code for a long time trying to figure this out, but I am having no luck. This issue is that I want to assign a value to the parameter boxId. When I click on a box in the webpage an alert will come up displaying that id. I have tried many things, but nothing seems to work. I'm a beginner, so I feel at this point there just must be something that I don't know how to do.
constructor function:
function Box (boxId, name, color, number, coordinates) {
this.boxId = boxId;
this.name = name;
this.color = color;
this.number = number;
this.coordinates = coordinates;
}
global variables:
var boxes = [];
var counter = 0;
var boxId = 0;
init function:
window.onload = init;
function init() {
var generateButton = document.getElementById("generateButton");
generateButton.onclick = getBoxValues;
var clearButton = document.getElementById("clearButton");
clearButton.onclick = clear;
}
function to get values and create new boxes:
function getBoxValues() {
var nameInput = document.getElementById("name");
var name = nameInput.value;
var numbersArray = dataForm.elements.amount;
for (var i = 0; i < numbersArray.length; i++) {
if (numbersArray[i].checked) {
number = numbersArray[i].value;
}
}
var colorSelect = document.getElementById("color");
var colorOption = colorSelect.options[colorSelect.selectedIndex];
var color = colorOption.value;
if (name == null || name == "") {
alert("Please enter a name for your box");
return;
}
else {
var newbox = new Box(boxId, name, color, number, "coordinates");
boxes.push(newbox);
counter++;
var boxId = counter;
}
addBox(newbox);
var data = document.getElementById("dataForm");
data.reset();
}
function that adds boxes to the page:
function addBox(newbox) {
for (var i = 0; i < newbox.number; i++) {
var scene = document.getElementById("scene");
var div = document.createElement("div");
div.className += " " + "box";
div.innerHTML += newbox.name;
div.style.backgroundColor = newbox.color;
var x = Math.floor(Math.random() * (scene.offsetWidth-101));
var y = Math.floor(Math.random() * (scene.offsetHeight-101));
div.style.left = x + "px";
div.style.top = y + "px";
scene.appendChild(div);
div.onclick = display;
}
}
function to display alert when box is clicked:
function display(e) {
var a = e.target;
alert(a.counter);
}
function to clear boxes:
function clear() {
var elems = document.getElementsByClassName("box");
for ( k = elems.length - 1; k >= 0; k--) {
var parent = elems[k].parentNode;
parent.removeChild(elems[k]);
}
}
All of the other functions work just fine. I keep running into the id showing up as "undefined" when I click it, or the counter displaying "0" in the console log, for everything I've tried.
You can do it like this.
First, in addBox() embed boxId as an tag's attribute like this:
div.setAttribute('data-boxId', newbox.boxId);
Then in display() you can retrieve it back:
alert(e.target.getAttribute('data-boxId'));
Please tell if you do not prefer this approach and I will post an alternative (closure things).
Edit: Add jsfiddle example http://jsfiddle.net/runtarm/8FJpU/
One more try. Perhaps if you change:
var boxId = counter;
to
boxId = counter;
It will then use the boxId from the outer scope instead of the one defined in the function getBoxValues()

Drawing bezier curve on html canvas

I need to draw a bezier curve defined by N control points which are stored in an array. I have a canvas which is 500px x 500px.
Here's the JSFiddle link : jsfiddle.net/HswXy
Entire JS code:
<script>
window.onload=function(){
var old_n=0,n=0;
var nrSelect = document.getElementById("mySelect");
var submit = document.getElementById("submit");
nrSelect.addEventListener("change",function(){
old_n=n;
n = nrSelect.selectedIndex;
var inputx,inputy,br;
if(document.getElementById("pointsdiv"))
{
for(i=1;i<=n;i++){
inputx = document.createElement('input');
inputy = document.createElement('input');
br = document.createElement('br');
inputx.type = "text";
inputy.type = "text";
inputx.size = 3;
inputy.size = 3;
inputx.id = "x_" + i;
inputy.id = "y_" + i;
inputx.value = "x_" + i;
inputy.value = "y_" + i;
inputx.addEventListener("focus",function(){if(this.value==this.id) this.value="";});
inputy.addEventListener("focus",function(){if(this.value==this.id) this.value="";});
document.getElementById("pointsdiv").appendChild(inputx);
document.getElementById("pointsdiv").appendChild(inputy);
document.getElementById("pointsdiv").appendChild(br);
}
document.getElementById("pointsdiv").id="pointsdiv_after";
}
else
{
if( old_n < n )
{
for(i=old_n+1;i<=n;i++){
inputx = document.createElement('input');
inputy = document.createElement('input');
br = document.createElement('br');
inputx.type = "text";
inputy.type = "text";
inputx.size = 3;
inputy.size = 3;
inputx.id = "x_" + i;
inputy.id = "y_" + i;
inputx.value = "x_" + i;
inputy.value = "y_" + i;
inputx.addEventListener("focus",function(){if(this.value==this.id) this.value="";});
inputy.addEventListener("focus",function(){if(this.value==this.id) this.value="";});
document.getElementById("pointsdiv_after").appendChild(inputx);
document.getElementById("pointsdiv_after").appendChild(inputy);
document.getElementById("pointsdiv_after").appendChild(br);
}
}
else
{
var parent;
for(i=n+1;i<=old_n;i++){
parent = document.getElementById("pointsdiv_after");
parent.removeChild(parent.lastChild);
parent.removeChild(parent.lastChild);
parent.removeChild(parent.lastChild);
}
}
}
});
//BEZIER CURVE
function factorial(n){
var result=1;
for(i=2;i<=n;i++){
result = result*i;
}
return result;
}
function Point(x,y){
this.x=x;
this.y=y;
}
var points = new Array();
function getPoint(t){
var i;
var x=points[0].x;
var y=points[0].y;
var factn = factorial(n);
for(i=0;i<n;i++){
var b = factn / (factorial(i)*factorial(n-i));
var k = Math.pow(1-t,n-i)*Math.pow(t,i);
// console.debug( i+": ",points[i] );
x += b*k*points[i].x;
y += b*k*points[i].y;
}
return new Point(x, y);
}
//--BEZIER CURVE
submit.addEventListener("click",function(){
if(n){
for(i=1;i<=n;i++){
var px = document.getElementById("x_"+i);
var py = document.getElementById("y_"+i);
points.push(new Point(parseInt(px.value,10),parseInt(py.value,10)));
// console.debug( points[i-1] );
}
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
context.beginPath();
console.debug( points[0].x, points[0].y );
context.moveTo(points[0].x, points[0].y);
var t=0.01;
while (t<=1)
{
//get coordinates at position
var p=getPoint(t);
// console.debug( p.x, p.y );
//draw line to coordinates
context.lineTo(p.x, p.y);
//increment position
t += 0.01;
}
context.stroke();
}
});
}
</script>
The problem is that it doesn't seem to work correctly. I'm testing it for 2 points now and it always starts in the upper left corner o the canvas (even if my first point is at let's say (250,250) and the length of the line is not the number of pixels it should be.. it's longer.
I'm no expert on canvas or geometry, but here is what I think: you shouldn't moveTo points[0] before drawing your faux line, since your getPoint function seems to lead you there. What I could see while debugging your code is that you first moved to (20,20), then drew a straight line to (roughly) (40,40), then started drawing gradually back to (20,20), generating that closed shape that wasn't what you were looking for.
A small (quick and dirty) change to your code made it start drawing a curve:
// DO NOT MOVE TO HERE
//context.moveTo(points[0].x, points[0].y);
var t = 0.01;
// MOVE TO THE FIRST POINT RETURNED BY getPoint
var p0 = getPoint(t);
context.moveTo(p0.x, p0.y);
t+=0.01;
// now loop from 0.02 to 1...
I'm sure you can refactor that into something better, as I said my changes were quick and dirty.
http://jsfiddle.net/HswXy/3/

Categories

Resources