Home > Software design >  i got this little question about my reset button in html
i got this little question about my reset button in html

Time:11-06

<!DOCTYPE html>
<html>
<head>

<style>
* {
    box-sizing: border-box;
}

/* Create three unequal columns that floats next to each other */
.column {
    float: left;
    padding: 10px;
    height: 501px;
}

.left, .right {
    text-align: center;
    margin-top: 10px;
    width: 270px;
    border: 5px solid brown;
    background-color: #bbb;
    overflow-y: scroll;
    overflow-x: hidden;
    
}

.middle {
    width: 620px;
}

canvas {
    border: 1px solid black;
}
</style>

<script type="text/javascript">
function allowDrop(ev) {
    ev.preventDefault();
}

function drag(ev) {
    var dragId = ev.target.id;
    ev.dataTransfer.setData("dragId", dragId);
    wearables.forEach(wearable => {if(wearable.id === ev.target.id){
        target = wearable;
    }})

    /*alternatives syntax for reference.
    wearables.forEach(function(wearable){
        if (wearable.id === ev.target.id) {
            target = wearable;
        }
    })*/

    hintSpan.innerHTML = "Drop me onto the "    target['dropId']   " of the girl.";

}

function drop(ev) {
    id = ev.target.id;
    //id = ev.dataTransfer.getData("id");
    wearables.forEach(function(wearable){
        if(wearable.id === id){
        target = wearable;
    }}) 
    /* alternatives syntax for reference.
        wearables.forEach(wearable =>{if(wearable.id === id){
        target = wearable;
    }})
    */
    const mousePos = {
        x: ev.clientX - canvas.offsetLeft,
        y: ev.clientY - canvas.offsetTop
      };
    const pixel = hitCtx.getImageData(mousePos.x, mousePos.y, 1, 1).data;
      const color = `rgb(${pixel[0]},${pixel[1]},${pixel[2]})`;
      const shape = colorsHash[color];
    if(shape.id === target.dropId){
        shape['dropped'] = target.id;
    }
    redraw(false);
}
</script>
</head>

<body>

<div >
  <div  id="leftDiv">
  </div>
  <div  id="midDiv">
    <canvas id="canvas" width="600" height="500" ondrop="drop(event)" ondragover="allowDrop(event)">
        Your browser does not support canvas.
    </canvas>
    <button id="reset">Reset</button>
    &nbsp; Canvas coordinate: (<span id="xPos">x</span>, <span id="yPos">y</span>)
    &nbsp; &nbsp; <span id="hint"></span>
  </div>
  <div  id="rightDiv">
  </div>
</div>

<script>
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');

const hitCanvas = document.createElement('canvas');
hitCanvas.width = 600;
hitCanvas.height = 500;
const hitCtx = hitCanvas.getContext('2d');


// uncomment this if you want to see the hidden canvas for testing or debugging
//document.getElementById('midDiv').appendChild(hitCanvas); 


const colorsHash = {};

// a function that generates a random color
function getRandomColor() {
    const r = Math.round(Math.random() * 255);
    const g = Math.round(Math.random() * 255);
    const b = Math.round(Math.random() * 255);
    return `rgb(${r},${g},${b})`;
}

// the sequence of drawing the wearables depends on the sequence of the elements listed here
const dropAreas = [
    {id: 'feet', positions: [ [250, 400], [350, 400], [350, 460], [250, 460] ], dropped: null},
    {id: 'hip',  positions: [ [240, 295], [360, 295], [360, 360], [240, 360] ], dropped: null},
    {id: 'body', positions: [ [205, 216], [400, 216], [400, 317], [205, 317] ], dropped: null},
    {id: 'head', positions: [ [210, 144], [220,  77], [300,  30], [374,  77], [390, 144] ], dropped: null},
];

// for each shape of droppable area, assign a unique random color
dropAreas.forEach(shape => {
    while (true) {
        const colorKey = getRandomColor();
        if (!colorsHash[colorKey]) {
            shape.colorKey = colorKey;
            console.log(colorKey);
            colorsHash[colorKey] = shape;
            return;
        }
    }
});

// the set of wearable items (dresses, shirts, pants, etc.)
const wearables = [
    {id: 'headwear1', pos: [222,  50], dropId: 'head', wardrobe: 'right', fPath: 'images/Headwear1.png'},
    {id: 'hat1',      pos: [179,   1], dropId: 'head', wardrobe: 'right', fPath: 'images/Hat1.png'},
    {id: 'hat2',      pos: [188,  12], dropId: 'head', wardrobe: 'right', fPath: 'images/Hat2.png'},
    {id: 'hat3',      pos: [205,   5], dropId: 'head', wardrobe: 'right', fPath: 'images/Hat3.png'},
    {id: 'dress1',    pos: [227, 210], dropId: 'body', wardrobe: 'left',  fPath: 'images/Dress1.png'},
    {id: 'dress2',    pos: [230, 215], dropId: 'body', wardrobe: 'left',  fPath: 'images/Dress2.png'},
    {id: 'shirt1',    pos: [220, 215], dropId: 'body', wardrobe: 'left',  fPath: 'images/Shirt1.png'},
    {id: 'shirt2',    pos: [246, 215], dropId: 'body', wardrobe: 'left',  fPath: 'images/Shirt2.png'},
    {id: 'pants1',    pos: [258, 300], dropId: 'hip',  wardrobe: 'right', fPath: 'images/Pants1.png'},
    {id: 'pants2',    pos: [258, 305], dropId: 'hip',  wardrobe: 'right', fPath: 'images/Pants2.png'},
    {id: 'shoe1',     pos: [251, 405], dropId: 'feet', wardrobe: 'right', fPath: 'images/Shoe1.png'},
];

const SCALE = 0.5;
var hintSpan = document.getElementById("hint");

// creates images of wearable items inside the left and right div's (representing the wardrobes)
wearables.forEach(wearable => {
    var img = new Image();
    img.id = wearable.id;
    img.src = wearable.fPath ;

    img.onload = function(){
        img.width = img.width * SCALE;
        img.draggable = true;
        img.ondragstart = drag;
        img.ondragend = function(){
            hintSpan.innerHTML ="";
            
        };
        var wardrobe = document.getElementById(wearable.wardrobe   "Div");
        var hr = document.createElement("hr");
        wardrobe.appendChild(img);
        wardrobe.appendChild(hr);
    }
});


function drawShape(context, shape) {
    context.beginPath();
    shape.positions.forEach(function(position,index){
    if (index === 0) {
        context.moveTo(position[0],position[1]);
    }
    else{
        context.lineTo(position[0],position[1]);
    }
    context.fillStyle = shape.colorKey;
    context.fill();
  });
}

// draw the shapes of droppable areas in the hidden canvas
dropAreas.forEach(shape => {
    drawShape(hitCtx, shape);
});

/* A test function which alerts a message when a mouse click is done within a droppable area on the visible canvas.
   A droppable area is predefined by drawing a colored shape in the hidden canvas.
   The width and height of the visible canvas and the hidden canvas are the same.
   We check the color of the pixel in the hidden canvas at the coordinates of the current mouse position.
   If the color can match to a shape via the colorsHash array, that means the click is upon a droppable area.
   This example is a helpful basis for you to learn how to implement the drop() function.
*/
canvas.addEventListener('click', (e) => {
    const mousePos = {
        x: e.clientX - canvas.offsetLeft,
        y: e.clientY - canvas.offsetTop
    };
    const pixel = hitCtx.getImageData(mousePos.x, mousePos.y, 1, 1).data;
    const color = `rgb(${pixel[0]},${pixel[1]},${pixel[2]})`;
    console.log(color);
    const shape = colorsHash[color];
    if (shape) {
        alert('click on shape: '   shape.id);
    }
});


var xSpan = document.getElementById('xPos');
var ySpan = document.getElementById('yPos');

canvas.addEventListener('mousemove', (e) => {
    const mousePos = {
        x: e.clientX - canvas.offsetLeft,
        y: e.clientY - canvas.offsetTop
    };
  xSpan.innerHTML = mousePos.x;
  ySpan.innerHTML = mousePos.y;
});


// draw background

const BG_SCALE = 1.02;
var bg = new Image();
bg.onload = drawBackground;
bg.src = "images/background/4.jpg";

function drawBackground() {
    ctx.save();
    ctx.globalAlpha = 0.6;  // make the image semi-transparent
    ctx.drawImage(bg,0,0,bg.width,bg.height,canvas.width/2-bg.width*BG_SCALE/2,canvas.height/2-bg.height*BG_SCALE/2,bg.width*BG_SCALE,bg.height*BG_SCALE);
    ctx.restore();
};

// draw an image
var girl = new Image();
girl.src = "images/Girl.png";
girl.onload = drawForeground;

function drawForeground() {
    ctx.drawImage(girl,0,0,girl.width,girl.height,canvas.width/2-girl.width*SCALE/2,canvas.height/2-girl.height*SCALE/2,girl.width*SCALE,girl.height*SCALE);

    // for each droppable area, if a wearable has been dropped onto it, then draw the wearable image on canvas
    dropAreas.forEach(shape => {
        var w = shape.dropped;
        if (w) {
            //console.log(w)
            wearables.forEach(function (wearable){
            if(w === wearable.id){
                var wear = new Image();
                wear.src = wearable.fPath;
                ctx.drawImage(wear,wearable.pos[0], wearable.pos[1], wear.width*SCALE, wear.height*SCALE);
                }
            })
            }           
        });
    
}

// Implement the reset button; reset will remove all weared items on the girl
var resetButton = document.getElementById("reset");
resetButton.addEventListener('click', function(){
    redraw(true);
});


function redraw(clear) {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    if (clear) {
    dropAreas.forEach(resetCanvas => {
         resetCanvas.dropped = null;
         console.log(resetCanvas)
        })
    /*
    for (var i = 0; i < dropAreas.length; i  ) {
        if(dropAreas.dropped != null){
    dropAreas.dropped = null;
    console.log(dropAreas)
    }*/

}
    drawBackground();
    drawForeground();

}

</script>
</body>
</html>

this is a little game problem my teacher told me to do. My question is, in the redraw(clear) function, Why would the forEach function work but not the for loop?

dropAreas.forEach(resetCanvas => {
         dropAreas.dropped = null;
         console.log(dropAreas.dropped)
        })

I also tried this coding replacing the one i currently have, it shows 4 nulls in my console log for dropAreas.dropped, but doesn't remove the image off the girl. It shows no errors in console, but i am curious why would it not work? thank you.

CodePudding user response:

Why would the forEach function work but not the for loop?

Look at what the forEach does:

dropAreas.forEach(resetCanvas => {
  resetCanvas.dropped = null;
  console.log(resetCanvas)
})

For each object in the dropAreas array, calling that object resetCanvas each time, set the dropped property on that object to null. And log that object to the console.

Then look at what your code does:

for (var i = 0; i < dropAreas.length; i  ) {
  if(dropAreas.dropped != null){
    dropAreas.dropped = null;
    console.log(dropAreas)
  }
}

For each object in the dropAreas array, set the dropped property for the array itself to null. And log the entire array to the console.

Your second attempt at the forEach makes the same mistake.

You're simply getting confused as to the difference between an array of objects and an object in that array. The objects themselves have a dropped property, the entire array itself does not.

As an analogy, think of the array as a basket of apples and the objects as the apples. Instead of trying to take a bite out of an apple, you're trying to take a bite out of the basket.


To correct the for loop, use the i indexer on the array to reference individual elements:

for (var i = 0; i < dropAreas.length; i  ) {
  if(dropAreas[i].dropped != null){
    dropAreas[i].dropped = null;
    console.log(dropAreas[i])
  }
}
  • Related