Activate when every single pixel within an element is see-through

I've designed a web page that includes two canvas elements stacked on top of each other. The purpose of this setup is to allow me to "erase" the top canvas and reveal an image loaded into the bottom canvas. So far, this functionality has been working perfectly.

Now, my goal is to trigger an event once the top canvas has been completely "erased," meaning that all of the pixels in the top context are transparent. I've searched for solutions on Stack Overflow and found methods using getImageData to check a specific pixel's alpha value. However, I'm struggling to find a way to determine when the very last pixel's alpha value equals 0.

Included below is my code, along with an unfinished attempt to achieve this using a for-loop and if statement. I have also encountered another issue where using getImageData results in a thin grey border appearing around two edges of my canvas.

Thank you in advance for any assistance!

window.onload = function() {
    //Move speaker image across page
    var speaker = document.getElementById('speaker');
    speaker.onload = MoveElement(speaker, "right", 1000);

    //Create canvases & contexts
    var canvas = document.getElementById('canvas');
    var ctxB = canvas.getContext('2d');
    var canvas2 = document.getElementById('canvas2');
    var ctxT = canvas2.getContext('2d');

    //Get waterfall image object
    var waterfall = document.getElementById('waterfall');

    //Set canvas w&h properties
    canvas.width = canvas2.width = .3*waterfall.width;
    canvas.height = canvas2.height = .3*waterfall.height;

    //Populate Bottom canvas with waterfall image
    ctxB.drawImage(waterfall, 0, 0, canvas.width, canvas.height);

    //Populate Top canvas with white rectangle
    ctxT.fillStyle = "white";
    ctxT.fillRect(0, 0, canvas2.width, canvas2.height);

    //Make Top canvas "erasable"
    canvas2.addEventListener('mousemove', event => {
        var x = event.offsetX;
        var y = event.offsetY;  
        const eraseSize = 125;
        ctxT.clearRect(x-eraseSize/2, y-eraseSize/2, eraseSize, eraseSize);
    })

    //Attempt to trigger an event when all pixels of top canvas have alpha = 0
    var imageDataTop = ctxT.getImageData(0, 0, canvas2.width, canvas2.height);
    console.log(imageDataTop);

    for (var i = 0; i < imageDataTop; i++) {
        if (imageDataTop.data[i] = 0) {
            //
        }

    }
}

function PlayAudio() {
    document.getElementById('boyfriend').play();
}


//Move an element in a given direction a certain distance
function MoveElement(element, direction, totalDistance) {
    //Determine horizontal or vertical direction
    var LeftOrTop = (direction=="left" || direction=="right") ? "left" : "top";
    
    //Set default frame distance
    var frameDistance = 150;

    //Adjust for backwards direction
    if (direction=="left" || direction=="up") {
        totalDistance *= -1;
        frameDistance = -1;
    }
    
    //Get style data object for element
    var elementStyle = window.getComputedStyle(element);

    //Get Left or Top position of element
    var positionValue = elementStyle.getPropertyValue(LeftOrTop).replace("px", "");

    //Apply direction and distance change to element
    var destination = (Number(positionValue) + totalDistance) + "px";

    function MoveFrame() {
        //If element reaches its destination...
        if (elementStyle.getPropertyValue(LeftOrTop) == destination) {
            //...stop the interval motion
            clearInterval(movingFrames);
        }
        //Otherwise, continue the interval movement
        else {
            elementStyle = window.getComputedStyle(element);
            positionValue = elementStyle.getPropertyValue(LeftOrTop).replace("px", "");
            element.style[LeftOrTop] = (Number(positionValue) + frameDistance) + "px";
        }
    }
    //Define time interval for movement
    var movingFrames = setInterval(MoveFrame, 500);
}
#stack {
    position: relative;
}
#stack canvas {
    position: absolute;
    display: block;
    left: 50%;
    transform: translateX(-50%);
    margin-top: 150px;
}

#speaker {
    position: absolute;
    top: 20px;

    animation-duration: 800ms;
    animation-name: fadein;
    animation-iteration-count: 10;
}
@keyframes fadein {
    from {
        opacity: 0.25;
    }
    50% {
        opacity: 1;
    }
    to {
        opacity: 0.25;
    }
}
<!DOCTYPE html>
{% load static %}
<html>
    <head>
        <meta charset="utf-8">
        <link rel="stylesheet" href="{% static 'entrance/entrance.css' %}">
        <script src="{% static 'entrance/entrance.js' %}"></script>
    </head>

    <body>
        <p hidden>
            <img src="{% static 'entrance/Waterfall.jpg' %}" alt="issue here" id="waterfall" />
        </p>
        
        <img src="{% static 'entrance/sound-icon.svg' %}" id="speaker" />
        <p id="test"></p>

        <audio id="boyfriend" source src="{% static 'entrance/02 30 Minute Boyfriend.mp3' %}" type="audio/mp3"></audio>
        <div id="stack" onmouseenter="PlayAudio()">
            <canvas id="canvas"></canvas>
            <canvas id="canvas2"></canvas>
        </div>
    </body>
</html>

Answer №1

When obtaining the dataimage, you will receive an array containing 4 bytes per point within the canvas. The first three bytes represent RGB colors, while the fourth byte indicates alpha transparency.

If the color is transparent, the fourth byte will be 0. To determine if erasing is complete, carefully examine each 4th byte in the array whenever erasing occurs. If a non-zero value is encountered, it signifies that erasing is not finished.

For further information, refer to this helpful resource: https://www.w3schools.com/tags/canvas_getimagedata.asp

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Tips for avoiding page reload when submitting a form with form.submit() in ReactJs

Is there a way to avoid the page from refreshing when triggering form submission programmatically in ReactJS? I have attempted to use this block of code: const myForm = () => <form onBlur={(e) => { if(!e.relatedTa ...

Retrieve the value of a DOM element within the document.ready function

After researching, I discovered a way to make my textArea resize when the page is fully loaded. $(document).ready(function() { // Handler for .ready() called. }); I decided to test it out and inserted the following code into the function: $(document). ...

Utilizing PHP for XML exportation and fetching it through AJAX to integrate it into the DOM, unfortunately, the XML content remains invisible

I've encountered a strange issue with a PHP script that generates valid XML output. I'm trying to fetch this data using an Ajax XMLHttpRequest call in the browser. Although Firebug confirms that the Ajax request is successful and the XML is vali ...

What is the best way to arrange list items in this manner?

I am facing challenges with aligning elements properly on the navigation bar. I would like the words (home, players, about, contact) to be vertically centered in relation to the heart logo. Here is how it currently appears: This is how I want it to look ...

Sending chosen choice to controller method

I'm working with a table that contains inputs and angular models. <td> <select class="form-control" id=""> <option ng-model="mfrNo" ng-repe ...

Looking to retrieve the value of an input element within an ng-select in Angular 6?

Currently, I am working on a project where I aim to develop a customized feature in ng-select. This feature will enable the text entered in ng-select to be appended to the binding item and included as part of the multiselect function. If you want to see a ...

Ways to display title attributes when focused using jQuery?

Typically, title attributes in all browsers only appear when the mouse hovers over them. I am looking to also display them when users are focused on them via keyboard navigation. Unfortunately, without using JavaScript, this cannot be achieved solely throu ...

Display an icon button when a user edits the text in a text field, and make it disappear once clicked on

Figuring out how to incorporate a v-text-area with an added button (icon) that only appears when the text within the text area is edited, and disappears once it is clicked on, has proven to be quite challenging. Below is a simplified version of my code to ...

Is there a way to programmatically simulate clicking on the "Cancel search" button?

I have a text input field with type "search". In order to perform UI testing, I need to simulate clicking on the "cancel search" button: The code for this specific input field is as follows: <input type="search" value="user"> Although the cancel b ...

Dynamically add index to attribute as it updates

Having an issue with my dynamic button element: <button v-on:click="changeRecord(element)" v-b-modal.modal-5>Aendern</button> This button is generated dynamically within a v-for loop. Instead of manually including the attribute name like v-b- ...

Tips for Loading a Selected Option from an Ajax Call in Angular JS on Page Load

How do I automatically set the selected option from an ajax call when the page loads? I am fetching zones using an ajax call and I want to trigger the change function of the zones on page load in order to set the selected option of the cities select box. ...

Using JQuery to automatically set the default selection when toggling the visibility of a div

I currently have a script that toggles the visibility of a div when selected: $('.showSingle').click(function () { $('.targetDiv').hide(); $('.showSingle').removeClass('greenactive'); $(this).addCla ...

Getting the value of a sibling select element when a button is clicked

Trying to retrieve the selected option value on button click has become a challenge due to multiple groups of buttons and select elements. The key seems to be using siblings somehow, but the exact method remains elusive... <div class="form-group" ng-re ...

What is the best way to retrieve all SVG objects within a specific area in an Angular application?

I am currently developing an SVG drawing application and have implemented a tool that enables users to select all shapes within a rectangular area. However, I am facing the challenge of detecting the SVG shapes located underneath the selected rectangle. ...

After making 5 Ajax get requests, there is no response being received

Currently, I'm facing an issue when trying to retrieve information from the MongoDB server to the frontend using an AJAX GET request. Everything works smoothly until I attempt to call the JavaScript function multiple times. Strangely, if I call the fu ...

Error: Module 'electron-prebuilt' not found

I am encountering an issue with my Electron app that utilizes Nightmare.js after compiling it into an .exe file using electron-packager. Everything functions properly until I click a button that triggers Nightmare.js, at which point I receive the followi ...

KeyBy lodash method stores values in an object using the specified property as keys

There are multiple items stored in an array: "objects": [ { "category": "XXXXX", "item_name": "over_pkg_0", "price": 230 }, { "category": "XXXXX", "item_name": "over_pkg_1", "price": 54 }, ...

An issue encountered with getServerSideProps in NextJS 12 is causing a HttpError stating that cookies are not iterable, leading

Currently, I have an application running smoothly on my localhost. However, when it comes to production, an unexpected error has popped up: Error: HttpError: cookies is not iterable at handleError (/usr/src/.next/server/chunks/6830.js:163:11) at sendReques ...

What could be causing my page's wrapper to shrink upon logging in?

After logging out, the background of my page wrapper expands to cover 100% of the page. However, once you log back in, it shrinks and adjusts to the width of the member bar... TO TEST USER ACCOUNT BELOW: USERNAME: TEST PASSWORD: TEST123 HTML FOR LOGGED ...

Unexpected Behavior when Passing @Input() Data Between Parent and Child Components in Angular 2 Application

I am currently in the process of abstracting out a tabular-data display to transform it into a child component that can be loaded into different parent components. The main aim behind this transformation is to ensure that the overall application remains "d ...