Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for transparent images #6

Open
stefandevo opened this issue Mar 22, 2019 · 8 comments
Open

Support for transparent images #6

stefandevo opened this issue Mar 22, 2019 · 8 comments

Comments

@stefandevo
Copy link

Related to #5

I changed the code a little bit to support transparent images too. Please check it out.
Basically, when assigned, I count the non-transparent pixels (for an image with transparent pixels this is import). Then when evaluating the reveal percentage, I count the non-transparent pixels again, and compare it to the original. That way you always have a correct percentage.

the new method:

    function getTotalPixels(ctx, width, height, stride) {
        if (!stride || stride < 1) stride = 1;
        const pixels = ctx.getImageData(0, 0, width, height);
        let total = 0;
        for (let i = 0; i < pixels.data.length; i += stride) {
            if (parseInt(pixels.data[i], 10) !== 0) total++;
        }
        return total;
    }

the modified methods:

function getFilledPercent(ctx, width, height, total, stride) {
        if (!stride || stride < 1) stride = 1;
        const pixels = ctx.getImageData(0, 0, width, height);

        let count = 0;
        for (let i = 0; i < pixels.data.length; i += stride) {
            if (parseInt(pixels.data[i], 10) !== 0) count++;
        }
        return 100 - Math.round(count / total * 100);
    }

an extra data value must be added:

totalPixels: 0
            drawImage() {
                const image = new Image();
                image.crossOrigin = 'Anonymous';
                image.src = this.imageUrl;
                image.onload = () => {
                    this.ctx.drawImage(image, 0, 0, this.cardWidth, this.cardHeight);
                    this.overlayLoaded = true;
                    this.totalPixels = getTotalPixels(this.ctx, this.cardWidth, this.cardHeight, 32);
                };
            },
            handleMouseMove(e) {
                ...

                this.handlePercentage(
                    getFilledPercent(this.ctx, this.cardWidth, this.cardHeight, this.totalPixels, 32),
                );
            },

And a small bug, where you can now set 100 as reveal percentage as well:

            handlePercentage(filledInPixels = 0) {
                if (filledInPixels >= this.finishPercent) this.reveal();
            },

With this you can now use a background image for the revealed image, and a image with transparent pixels but with a small part as the scratch area. Please find attached these two files as an example:

foreground01
background01

@alyoshark
Copy link
Owner

Thanks for the work. I'll go over the details later when I recover from my cold T_T

@stefandevo
Copy link
Author

Any news?

@OrhanTozan
Copy link
Contributor

@stefandevo Consider migrating the proposed code changes to a pull request?

@alyoshark
Copy link
Owner

Kinda busy recently. Will definitely look into this.

@alyoshark
Copy link
Owner

@stefandevo your modification is indeed a very reasonable change. The only issue I'm thinking is for transparent images, revealing percentage could be a bit hard to define intuitively: Should we go for "total percentage revealed" or "extra percentage scratched on top of the original".

And with some more experience in Vue, my original code now looks a bit entangled with anti-patterns in Vue SFC. I'll find a time to refactor it to a newer version and port your snippets in, but maybe not this version just yet (unless I see more pressing need for people using the feature), as I'm a bit wary of the layered complexity on top of the original spaghetti.

In the meantime I'm open to suggestions on the specification of finishPercent.

@stefandevo
Copy link
Author

Ok, I implemented it in a fork for me as I needed this in production. My thought is, when you deliberate want to use transparent pixels to only overlay a portion of your image, then you would also count the percentage finished upon the total non-transparent pixels.

@alyoshark
Copy link
Owner

Hmm... Makes sense, so will be "total revealed" then

@dylan-conlin
Copy link

@stefandevo Do you have a link to the fork you created? I think I may be running into this issue as well.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

4 participants