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!

https://i.sstatic.net/gHs0X.png

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

Is utilizing React function components the most effective solution for this problem?

export default function loginUserUsing(loginType: string) { const [state, setState] = useState(loginType); function login() { // body of the login function } function oauth() { // body of the oauth function login(); ...

What is the procedure for submitting all checkbox values through Google Apps Script?

My web app created using Google Apps Script can generate a custom table of data for users to select for calculations. I use Google Sheets to populate the table with values and checkboxes, but note that the table size may vary depending on the user. <fo ...

"Interactive feature allowing database updates on a web page without the need for a page

I have a like button that contains an ID pulled from a database. My goal is to click the like button, update the database, and then switch it to unlike without having to reload the page. Below is the code for clarity: **index.php: ** <script type=&quo ...

What is the best way to utilize the ajax factory method in order to establish a $scoped variable?

One issue I frequently encounter in my controllers is a repetitive piece of code: // Get first product from list Product.get_details( id ) .success(function ( data ) { // Setup product details $scope.active_product = data; }); To avoid this ...

The custom radio button is not showing up on iOs Safari

My code for custom radio buttons using CSS is as follows: input[type=radio]{ display:none; } .radio-options label::before { content: "\2b24"; color:#e2e2e2; display: inline-block !important; width: 17px; height: 17px; vert ...

A step-by-step guide on deleting an element within a div using jQuery

I am attempting to delete an HTML element using JQuery like this $('#' + divId + ' .settings_class').remove('.print_settings'); This code does not result in an error or remove the specified html element, however, the selecto ...

Associative TypeScript Arrays

I'm attempting to organize reservations based on business ID in order to achieve a specific end result. Here is the desired output: [ [businessID1] => [Object1,Object2, Object3], [businessID2] => [Object1,Object2], [businessID3] => [Obje ...

Tips for handling an InvalidSelectorException in Selenium when logging into a website

I've been working on automating website logins using Selenium and here is the code I have written: from selenium import webdriver driver = webdriver.Chrome() driver.get("https://abcde.com") assert "xxx" in driver.title user = driver.find_element_by ...

Retrieving historical data from a MySQL database to display in a div element

My main page features a button that opens a popup. Upon closing the popup, a script is triggered to call a PHP file for selecting data from the database. This selected data is then appended to a specific div within the main page: if (win.closed !== false ...

The background image is cropped, causing a scroll bar to be added

I've been attempting to add a background image to my HTML using the code below: body { margin: 0; background: url('images/lightning.jpg') no-repeat center center fixed; background-size: cover; -webkit-background-size: cover; -mo ...

Using two modal popups while passing an identifier

UPDATE: In my investigation, I discovered that a plain input tag without MVC RAZOR works as expected: <input type="text" class="hiddenid2" /> //WORKED However, when using the following code, it does not work: @Html.Editor("id", "", new { htmlAtt ...

HTML formatting for text

I recently created an HTML website using Dreamweaver. I faced an issue while trying to design a section within an article using tables to incorporate both text and images. Unfortunately, the tables did not have rounded edges as I desired. I am reaching out ...

Regular expression that prohibits the acceptance of numbers with leading zeros

Below is the directive I am using to ensure that the input consists purely of numbers from 0-9. import { Directive, HostListener, ElementRef } from "@angular/core"; @Directive({ selector: "[numbersOnly]", }) export class OnlynumberDi ...

The shadow is obscured by a block that has an 'overflow: scroll' property

One block on the left displays the list, while another shows detailed information with a shadow effect. The issue arises when the left block has 'overflow: scroll', causing elements' backgrounds to spill over the shadow. .div-left { flo ...

Creating dynamic routes for every page fetched from the API in Next.js

Hello everyone, Recently, my journey with NodeJS just commenced and I have been exploring API routes in NextJS as it provides an easy setup and clear visibility of the processes. While I have a grasp on creating basic get requests, I am now intrigued by s ...

How can JavaScript effectively retrieve the JPEG comment from a JPEG file?

How can one properly retrieve the JPEG comment field (not EXIF, but the COM field) from a JPEG file using JavaScript, particularly when running node on the command line? While there are several libraries available for reading EXIF data in JavaScript, I ha ...

Encountering difficulties with showing contact images in phonegap using angularjs

In my project, I encountered an issue where I can fetch and display the contact photo using simple HTML and JavaScript. However, when I attempt to do the same using AngularJS model, I encounter an error. Below is the code snippet that I am struggling with: ...

dissecting mongo queries using nodes

I am thinking about organizing my mongo db queries into a separate js file to make it easier to reuse the code. I have tried the format below but it doesn't seem to work. Does anyone have any suggestions on how I could accomplish this? queries.js va ...

Transfer the imageURI to a different HTML page

My mobile app, created using PhoneGap, allows users to select an image from their album. I want to pass that selected image and display it on another HTML page. Does anyone have any suggestions on how to achieve this? Below is the code snippet: selectImag ...

Issue on Heroku with Discord.js displaying a "Service Unavailable" message

Encountered a strange error while trying to launch my discord bot on heroku. Previously, I implemented a command handler for the bot to organize commands in separate files but faced multiple code errors. With the help of a member from this community, all e ...