Open In App

Scratch Card Using React js

Last Updated : 25 Jul, 2024
Comments
Improve
Suggest changes
Like Article
Like
Report

In this article, we will build a scratch card using ReactJS. A scratch card contains a reward; when the user scratches that card, the color present on the card will start erasing. And after erasing, the color content (reward) will be visible.

Preview:

Scratch-Card-Using-React-js

Prerequisite

Steps to Create the project:

  • Create a react application by using this command
npx create-react-app random-meal-generator
  • After creating your project folder, i.e. random-meal-generator, use the following command to navigate to it:
cd random-meal-generator

Project Structure

Package.json

"dependencies": {
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
}

Approach

  • InitializeCanvas: A gradient backdrop with randomly picked prize value is used to setup the first look of the scratch card.
  • checkIfTouchDevice: Check whether the user’s device is touch capable, and use different event handlers for touch and mouse devices.
  • getMouseCoordinates: Gets current mouse/touch coordinates in canvas’ space.
  • canvasElement: Detects dragging via mouse or touch, updates the scratch area.
  • scratch: Reveals the hidden content by erasing the top layer with destination-out global composite operation and updates the canvas based on the user’s interactions.
  • The useEffect hook is used to initialize the canvas of the scratch card. This canvas is initialized with the gradient filled background and with a hidden prize value. Users can use mouse or touch events to interact with the card.

Example:

CSS
* {
    padding: 0;
    margin: 0;
    box-sizing: border-box;
}

body {
    height: 100vh;
    background: #eee;
}

.container {
    position: absolute;
    transform: translate(-50%, -50%);
    top: 50%;
    left: 50%;
    border-radius: 0.6em;
}

.base,
#scratch {
    height: 200px;
    width: 200px;
    position: absolute;
    transform: translate(-50%, -50%);
    top: 50%;
    left: 50%;
    text-align: center;
    cursor: grabbing;
    border-radius: 2em;
}

.base {
    background-color: #ffffff;
    font-family: 'Poppins', sans-serif;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    box-shadow: 0 1.2em 2.5em rgba(16, 2, 96, 0.15);
}

.base h3 {
    font-weight: 600;
    font-size: 1.5em;
    color: #17013b;
}

.base h4 {
    font-weight: 400;
    color: #746e7e;
}

#scratch {
    -webkit-tap-highlight-color: transparent;
    -webkit-touch-callout: none;
    -webkit-user-select: none;
    user-select: none;
}
JavaScript
import React, { useEffect, useState } from "react";
import "./App.css";

const App = () => {
    const [prizeValue, setPrizeValue] = useState("$10"); // Default value

    useEffect(() => {
        const canvasElement = document.getElementById("scratch");
        const canvasContext = canvasElement.getContext("2d");
        let isDragging = false;

        const initializeCanvas = () => {
            const gradient = canvasContext.createLinearGradient(0, 0, 135, 135);
            gradient.addColorStop(0, "#d63031");
            gradient.addColorStop(1, "#fdcb6e");
            canvasContext.fillStyle = gradient;
            canvasContext.fillRect(0, 0, 200, 200);

            // Generate a random prize value from the available options
            const prizeOptions = [
                "$1", "$5", "$10", "$20", "$25", "$30", "$35", "$40", "$45", "$50"
            ];
            const randomPrize = prizeOptions[Math.floor(Math.random() * prizeOptions.length)];
            setPrizeValue(randomPrize);
        };

        const scratch = (x, y) => {
            canvasContext.globalCompositeOperation = "destination-out";
            canvasContext.beginPath();
            canvasContext.arc(x, y, 12, 0, 2 * Math.PI);
            canvasContext.fill();
        };

        const getMouseCoordinates = (event) => {
            const rect = canvasElement.getBoundingClientRect();
            const x = (event.pageX || event.touches[0].pageX) - rect.left;
            const y = (event.pageY || event.touches[0].pageY) - rect.top;
            return { x, y };
        };

        const handleMouseDown = (event) => {
            isDragging = true;
            const { x, y } = getMouseCoordinates(event);
            scratch(x, y);
        };

        const handleMouseMove = (event) => {
            if (isDragging) {
                event.preventDefault();
                const { x, y } = getMouseCoordinates(event);
                scratch(x, y);
            }
        };

        const handleMouseUp = () => {
            isDragging = false;
        };

        const handleMouseLeave = () => {
            isDragging = false;
        };

        const isTouchDevice = 'ontouchstart' in window;

        canvasElement.addEventListener(isTouchDevice ? "touchstart" : "mousedown", handleMouseDown);
        canvasElement.addEventListener(isTouchDevice ? "touchmove" : "mousemove", handleMouseMove);
        canvasElement.addEventListener(isTouchDevice ? "touchend" : "mouseup", handleMouseUp);
        canvasElement.addEventListener("mouseleave", handleMouseLeave);

        initializeCanvas();

        // Cleanup event listeners on unmount
        return () => {
            canvasElement.removeEventListener(isTouchDevice ? "touchstart" : "mousedown", handleMouseDown);
            canvasElement.removeEventListener(isTouchDevice ? "touchmove" : "mousemove", handleMouseMove);
            canvasElement.removeEventListener(isTouchDevice ? "touchend" : "mouseup", handleMouseUp);
            canvasElement.removeEventListener("mouseleave", handleMouseLeave);
        };
    }, []);

    return (
        <div className="container">
            <div className="base">
                <h4>You Won</h4>
                <h3>{prizeValue}</h3>
            </div>
            <canvas
                id="scratch"
                width="200"
                height="200"
                style={{
                    cursor: 'url("https://media.geeksforgeeks.org/wp-content/uploads/20231030101751/bx-eraser-icon.png"), auto'
                }}
            ></canvas>
        </div>
    );
};

export default App;
  • Type the following command in the terminal:
npm start
  • Type the following URL in the browser:
 http://localhost:3000/

Output:

mr-(2)



Similar Reads