Track hand rotational angle – Leap + Javascript

In this tutorial, we are going to teach you how you can track your hand rotation using Leap Motion Controller. Leap Motion Controller is a device that allows you to detect your hand motions and gestures, and perform any desired action on them. It provides SDK in Java, Javascript, Python, C++, and Unreal Engine. We will be using Javascript in this tutorial.

You can buy the Leap Motion Controller from their official website. After buying, connect the device with your computer using a USB or USB-C port. Then download the SDK from here and do the installation.

If you prefer the video tutorial:

From the above video, you can see what we are going to create. So you will need a Doctor Strange time-spell video and some images. You will also need the Leap JS library to connect with Leap Motion Controller. You can find all 3 in the source files below.

Setup the Project

The following code helps you to reverse a video and concatenate 2 videos using FFmpeg:

// reverse a video
// ffmpeg -i Pentagramm2_green.mp4 -vf reverse reversed.mp4

// concatenate 2 videos
// ffmpeg -i Pentagramm2_green.mp4 -i reversed.mp4 -filter_complex "[0:v] [0:a] [1:v] concat=n=2:v=1:a=1 [v] [a]" -map "[v]" -map "[a]" output.mp4

Then create a video tag for the time-spell video.

<video src="output.mp4" muted id="time-spell"></video>

After that, create a div to show the image and text below it.

<div style="position: absolute; right: 50px; top: 50px;">
    <img src="images/2021.JPG" id="image" />
    <h1 id="title">2021</h1>
</div>

Now include the Leap JS library in your project.

<script src="leap-0.6.4.min.js"></script>

Then apply some CSS styles to display the video, image, and text properly.

<style>
    /* remove margin and set background color as black */
    body {
        margin: 0px;
        background-color: black;
    }

    /* set width of time spell and its position */
    #time-spell {
        width: 1200px;
        position: absolute;
        left: -275px;
        top: 30px;
    }

    /* set width and height of image and fit inside container */
    #image {
        width: 800px;
        height: 600px;
        object-fit: contain;
    }

    /* set color, position, alignment, font size and background color of image text */
    #title {
        color: white;
        position: relative;
        bottom: 129px;
        text-align: center;
        font-size: 70px;
        background-color: rgba(0, 0, 0, 0.7);
    }
</style>

Then create an array of images and their text in Javascript.

<script>

    // list of images and their text
    var images = [{
        "src": "images/2021.JPG",
        "title": "2021"
    }];

    // index is out of bound right now
    var index = images.length;

</script>

After that, initialize some variables that we will be using throughout the tutorial.

// total duration of time spell video
var totalDuration = 40;

// state of time spell (back or forward)
var state = "";

// previous state of time spell
var previousState = "";

// hand rotation from Leap Motion Controller
var handRotation = "";

// is time spell start rotating
var isMediaPlaying = false;

// video tag
var media = document.getElementById("time-spell");

Leap motion controller connection

Now is the time to connect our Javascript app with Leap Motion Controller.

// setup Leap loop with frame callback function
var controllerOptions = {};

Leap.loop(controllerOptions, function(frame) {
    // get all hands in frame
    var hands = frame.hands;

    // if there is any hand
    if (hands.length > 0) {

        // get the first hand
        var hand = hands[0];

        // ignore if the hand is left
        if (hand.isLeft) {
            return false;
        }

        // get direction of hand (x,y,z co-ordinates)
        var axis = hand.direction;

        // get x-axis
        axis = axis[0];

        if (axis > 0 && axis < 0.9) {
            // if hand is rotated to right
            handRotation = "right";
        } else if (axis > -0.09 && axis < -0.01) {
            // if hand is in center (no rotation)
            handRotation = "center";

            media.pause();
        } else if (axis < 0 && axis < -0.5) {
            // if hand is rotated to left
            handRotation = "left";
        }
    } else {
        // if there is no hand in the frame, simply pause the time spell
        if (media != null) {
            media.pause();
        }
    }
});

For explanation, comments have been added with each line. Now we need to call a function every 0.5 seconds and rotate the time spell to the left if the hand is rotated to left, and right if the hand is rotated to right. Also, it will call a function to change the image as per hand rotation.

// called every 0.5 seconds
setInterval(function () {
    
    // if hand is rotating to right
    if (handRotation == "right") {
        
        // only called once to rotate time spell
        if (state == "") {
            // rotate to right
            mediaBackward();
        }

        // if time spell starts rotating
        if (isMediaPlaying) {
            // show next image
            nextImage();
        }

        // make it empty to give a delay to show next image
        handRotation = "";
    } else if (handRotation == "left") {

        // only called once to rotate time spell
        if (state == "") {
            // rotate to left
            mediaForward();
        }

        // if time spell starts rotating
        if (isMediaPlaying) {
            // show previous image
            previousImage();
        }

        // make it empty to give a delay to show previous image
        handRotation = "";
    } else if (handRotation == "center") {
        // pause the time spell, when hand is in center of Leap Motion Controller
        media.pause();
    }
}, 500);

Now we just need to create these 4 functions called from the above code.

// when hand is rotated right
function mediaBackward() {

    // "back" means reverse
    state = "back";

    // starts rotating time spell
    media.play();

    // current time of video
    var currentTime = media.currentTime;

    // if video stops playing
    if (currentTime <= 0) {
        // starts from middle to move right
        currentTime = totalDuration / 2;
    }

    // this condition becomes true only when the
    // time spell was rotating forward (left side)
    if (previousState != state) {
        // change direction of time spell
        var newTime = totalDuration - currentTime;
        media.currentTime = newTime;
    }
}

// when hand is rotated left
function mediaForward() {

    // "forward" means original video
    state = "forward";

    // starts rotating time spell
    media.play();

    // current time of video
    var currentTime = media.currentTime;

    // if video stops playing
    if (currentTime <= 0) {
        // starts from zero to move left
        currentTime = totalDuration;
    }

    // this condition becomes true only when the
    // time spell was rotating backward (right side)
    if (previousState != state) {
        // change direction of time spell
        var newTime = totalDuration - currentTime;
        media.currentTime = newTime;
    }
}

// show next image from images array
function nextImage() {
    // increment the index
    index++;

    // check if the index is out of bound
    if (index >= images.length || index < 0) {
        return false;
    }

    // get source of image
    var src = images[index].src;

    // get text of image
    var title = images[index].title;

    // update image
    document.getElementById("image").setAttribute("src", src);

    // update title
    document.getElementById("title").innerHTML = title;
}

// show previous image from images array
function previousImage() {
    // decrement the index
    index--;

    // check if the index is out of bound
    if (index < 0 || index >= images.length) {
        return false;
    }

    // get source of image
    var src = images[index].src;

    // get text of image
    var title = images[index].title;

    // update image
    document.getElementById("image").setAttribute("src", src);

    // update title
    document.getElementById("title").innerHTML = title;
}

Finally, 2 event listeners are added to check when the time spell is rotating and when is paused. Based on that, we will set our variables to change images.

// called when the time spell starts rotating
media.onplaying = function () {
    // set the variable to true
    setTimeout(function () {
        isMediaPlaying = true;
    }, 100);
};

// called when the time spell is paused
media.onpause = function () {
    // get the previous state
    previousState = state;

    // set the current state as empty
    state = "";
    
    // set the variable to false
    isMediaPlaying = false;
};

Following this tutorial, you will be able to track hand rotations using Leap motion controller and Javascript.

Download source code:

[wpdm_package id=’1271′]

Watermark image after upload – PHP, No Library

In this tutorial, we will teach you how you can put a watermark on an image uploaded by a user. You might have seen websites that allow you to upload images, but when you try to download them, they put their watermark on your image and ask you to pay to remove it. So let’s learn how they do this.

First I am going to create a form where we will show the input type file to select the image. Its method will be POST and the action will be “index.php”. The encoding (enctype) type must be multipart/form-data. This is necessary for uploading files. Then we are going to show a label that says “select file” and an input type file. The name attribute on the input type file will be used on the PHP side. It will also have an attribute accept=”image/*”, which means this input field will accept only image type, for example, PNG or JPEG, etc, but no PDF or DOCX type of files will be selected in this field. Finally, the form will have a submit button. Submit button will have a name attribute so we can know when this form is submitted.

Select a file

<form method="POST" action="index.php" enctype="multipart/form-data">

	<p>
		<label>Select file</label>
		<input type="file" name="image" accept="image/*" />
	</p>

	<input type="submit" name="submit" value="Upload" />
</form>

If you run the code now, you will see a form with an input type file and a submit button. Now we need to write the PHP code to handle this form.

Apply the watermark

First, we will check if the form is submitted.

<?php

if (isset($_POST["submit"]))

Then we will save the user uploaded image in a file named “image.png” because, in order to put a watermark on it, the file must be stored in our server.

move_uploaded_file($_FILES["image"]["tmp_name"], "image.png");

Then we need to get this image as an object. So call imagecreatefromjpeg function if your image was a JPEG image, imagecreatefrompng if it is a PNG. Parameter will be the path of saved image file.

$image_obj = imagecreatefromjpeg("image.png");

Similarly, we will create an object of our watermark image, which is a PNG image.

$watermark = imagecreatefrompng("watermark.png");

Then we will define the margin from the right and from the bottom, since we do not want the watermark to stick to the corners, we want a little margin.

$margin_right = 10;
$margin_bottom = 10;

Then we are going to get the watermark image width and height in a separate variable.

$watermark_width = imagesx($watermark);
$watermark_height = imagesy($watermark);

Now comes the tricky part. We need to tell the X and Y coordinates of original image where we will place the watermark. The X position from left will be width of uploaded image, minus width of watermark image, minus margin from right.

$destination_x = imagesx($image_obj) - $watermark_width - $margin_right;

Similarly, the Y position from top will be height of uploaded image, minus height of watermark image, minus margin from bottom.

$destination_y = imagesy($image_obj) - $watermark_height - $margin_bottom;

Now we need to copy the watermark image in user uploaded image. The syntax of this function is:

// imagecopy(dst_im, src_im, dst_x, dst_y, src_x, src_y, src_w, src_h)

Our destination image is the image uploaded by user. Source image is the watermark image. Destination x and y are just we calculated, I will explain this as well. And source x and y will be zero, because we do not want any margin in our watermark image. And finally the width and height of our source image which is watermark image.

imagecopy($image_obj, $watermark, $destination_x, $destination_y, 0, 0, $watermark_width, $watermark_height);

Now let me explain the calculation we did above.

Explaining X, Y co-ordinates

width of user image = 2560
width of watermark image = 640
margin from right = 10

2560 - 640 - 10 = 1910 = x

height of user image = 1600
height of watermark image = 345
margin from bottom = 10

1600 - 345 - 10 = 1245 = y

First is destination_x variable. The width of image object is 2560px, minus the width of watermark is 640px, minus the margin right which is 10. That equals 1910, so our watermark will be placed at 1910 on X axis from left. Now come to destination_y variable, height of user uploaded image is 1600px, it will be different for each image because user can upload image of any resolution. I am writing these values as sample. So the 1600px is the height of user uploaded image. Minus the height of watermark, which is 345px. Minus margin from bottom that is 10. That equals 1245. So our watermark image will be placed at 1245 on Y axis from top.

1910 + 640 = 2550
1245 + 345 = 1590

Now when the watermark is placed at 1910 from left and it has a width of 640px, then that equals 2550 which is 10px less than the width of user image, which is 2560px. So there is a difference of 10px, which means there will be a margin of 10px from right. Similarly, when the watermark is placed at 1245 from the top and it has a height of 345px, then that equals 1590 which is again 10px less than the height of the user image, which is 1600px. So it will have a margin of 10px from the bottom.

Generating watermarked image

Now the watermark image object has been copied to the user uploaded image object using imagecopy function above. Now we need to generate that image.

imagepng($image_obj, "output.png");

The first parameter will be an image object, which is a user object along with a watermark object because the watermark image has been copied to it. And second, will be the path of the output file.

Finally, we are going to destroy the image objects we just created for user-uploaded images and watermark image to free up the memory.

imagedestroy($image_obj);
imagedestroy($watermark);

Also, we saved the user image using the move uploaded file function because we need the image to be stored before putting a watermark on it. Now the watermark is placed, so we have no need for the original user-selected picture, so we are going to delete it using the unlink function.

unlink("image.png");

If you run the code now, select an image, and upload it, you will see that the original image was saved as image.png and the output.png is being rendered for a few seconds. When the output.png is completely rendered then the original image.png was automatically deleted because we have used the unlink function.

Complete code

<?php

if (isset($_POST["submit"]))
{
	move_uploaded_file($_FILES["image"]["tmp_name"], "image.png");
	$image_obj = imagecreatefromjpeg("image.png");

	$watermark = imagecreatefrompng("watermark.png");

	$margin_right = 10;
	$margin_bottom = 10;

	$watermark_width = imagesx($watermark);
	$watermark_height = imagesy($watermark);

	$destination_x = imagesx($image_obj) - $watermark_width - $margin_right;
	$destination_y = imagesy($image_obj) - $watermark_height - $margin_bottom;

	// imagecopy(dst_im, src_im, dst_x, dst_y, src_x, src_y, src_w, src_h)
	imagecopy($image_obj, $watermark, $destination_x, $destination_y, 0, 0, $watermark_width, $watermark_height);

	// 2560 - 640 - 10 = 1910
	// 1600 - 345 - 10 = 1245

	// x = 1910 + 640 = 2550
	// y = 1245 + 345 = 1590

	imagepng($image_obj, "output.png");

	imagedestroy($image_obj);
	imagedestroy($watermark);

	unlink("image.png");
}

?>

The final image will be of the same quality as of original image. If you face any problems in following this, kindly mention them in the comments section below.

How you can also resize the image without stretching in PHP by following this tutorial.

[wpdm_package id=’1262′]

Social networking site in Laravel – Node JS, Socket IO

When you hear the word “social networking site”, the first name that came to your mind must be Facebook. Then Instagram, Twitter, etc. We create a social networking site project just to give you an idea of how things work. It is not the exact code used in tech giants like Facebook. But it gives you an idea of how they do it.

Demo

FeaturesFreePremium ($100)
AuthenticationYesYes
Profile UpdateYesYes
Create posts (with images and videos)YesYes
Like, comments and repliesYesYes
Share postsYesYes
Friends post on your wallYesYes
Search usersYesYes
Create friendsYesYes
Admin panelYesYes
Email verificationNoYes
Reset passwordNoYes
NotificationsNoYes
Realtime post update and deleteNoYes
NoYes
Search pages, and groupsNoYes
Create pages, and groupsNoYes
Private user-to-user chatNoYes
List of people who viewed your profileNoYes
Infinite scrollNoYes
people who liked and shared your postNoYes
Chat messages encryptionNoYes
Customer supportNoYes
Ban users, posts, pages, and groupsNoYes
Adult image validationNoYes
Show emails generated by systemNoYes
Online / offline statusNoYes
User last sceneNoYes
User activity logsNoYes

Previously, we create a Social Networking Site in Node JS and Mongo DB. But many people were asking that we create the same project in Laravel too, for PHP lovers. So here it is.

We have added 4 more features to it.

  1. Track system mails: All the emails sent from the system (Mail::to) function will be stored in a database. And the admin can view all the emails from the admin panel.
  2. Online/offline status: Now you can know when your friends are online and when they are offline. This will be helpful because you can just leave a message if the person is currently offline.
  3. Last scene of the user: You can also see your friend’s last scene active. This will help in situations like earthquakes etc. you can know which friends are not active in recent times.
  4. Track user activity: Admin can view the activities of users like when they are logged in when they created a page when they joined a group etc.

Load more Node JS button with Mongo DB

In this tutorial, we are going to teach you how you can create a load more Node JS button with MongoDB in your web project. “Load more” means that we will be displaying a few records, let’s say 5 when the page loads. Then we will display a button that when clicked will fetch the next 5 records. It is similar to the Facebook infinite scroll, where when you reach the end of the page, it automatically fetched the next posts. If you prefer a video tutorial over a textual tutorial, you can find it below:

Setup the server

Make sure you have installed Node JS and Mongo DB in your system. To view the data in Mongo DB, you will need a software called Mongo DB Compass. That can be installed during Mongo DB installation. Using Mongo DB Compass, create a database named “loadmore_nodejs_mongodb”. Inside this database, you need to create a collection named “users”. Inside this collection, you can add 10 records for testing. I have added the name and age of each user, the ID is automatically generated by Mongo DB.

Then you need to create an empty folder anywhere on your computer. And create a new file inside it named “server.js”. At the same time, open your command prompt or Terminal in this folder. You can run the following command to enter this folder:

cd "path of folder"

While being inside the folder, run the following command to initialize it as an NPM:

npm init

After that, you need to install some modules using the following command:

npm install express http mongodb ejs express-formidable
  • We will be using an express framework.
  • HTTP module will be used to start the server at a specific port.
  • Mongo DB module will be used to connect and interact with the Mongo DB database.
  • EJS will be used to render HTML files.
  • Express formidable will be used to receive HTTP POST values, which we will be sending from AJAX.

If you do not have a nodemon module you can install it with this command:

npm install -g nodemon

Nodemon command helps you to automatically restart the server if there is any change in the server.js file. Now in server.js, initialize express framework. Then create an HTTP server object and start the server at port 3000.

// initialize express framework
var express = require("express");
var app = express();
 
// create http server
var http = require("http").createServer(app);

// start the server
http.listen(3000, function () {
    console.log("Server started at port 3000");
});

Run nodemon command to start the server.

nodemon server.js

Connecting Node JS with Mongo DB

Now we need to connect our Node JS Express app with Mongo DB. We have already installed the Mongo DB module. Now we need to include the Mongo DB and Mongo Client objects. Place the following lines in your server.js file before calling the HTTP listen function:

// include mongo DB module
var mongodb = require("mongodb");
var mongoClient = mongodb.MongoClient;

Now after line 10 from previous code, place the following lines to connect with database:

// connect with mongo DB server and database
mongoClient.connect("mongodb://localhost:27017", {
    useUnifiedTopology: true
}, function (error, client) {
    var database = client.db("loadmore_nodejs_mongodb");
    console.log("Database connected.");
});

Display HTML file

Now we need to show an empty table where data will be populated dynamically. We will be using EJS to render the HTML file. First, we need to tell our Express app that we will be using the EJS engine. So add the following lines before connecting the HTTP server in server.js:

// set the view engine as EJS for displaying HTML files
app.set("view engine", "ejs");

Now we need to create a GET route that when accessed from the browser will display an HTML page. Place the following lines after line 6 from the previous code:

// create a GET HTTP route to show page
app.get("/", function (request, result) {
    // render an HTML page
    result.render("index");
});

Now we need to create a folder named “views” and inside this folder, create a file named “index.ejs”. Inside this file, we will create a table, and give an ID to the <tbody> because we will be displaying data dynamically. And also a load more button.

<!-- views/index.ejs -->

<table>
    <thead>
        <tr>
            <th>ID</th>
            <th>Number</th>
            <th>Age</th>
        </tr>
    </thead>

    <tbody id="data"></tbody>
</table>

<button type="button" onclick="getData();">
    Load More
</button>

Now you can access it by entering the following URL in your browser:

http://localhost:3000/

Get data from Mongo DB

Now we need to fetch data from the database in which a way that it will get 2 records each time a button is clicked. But the first 2 records will be fetched when the page loads. So create a script tag and create a variable that will be incremented each time that button is pressed. This variable will be used to skip the records to fetch the next ones.

<script>

    // Starting position to get new records
    var startFrom = 0;

    window.addEventListener("load", function () {
        // Calling the function on page load
        getData();
    });

</script>

Now we need to create that getData() function in index.ejs file. This will send an AJAX request to the route “load-more” with a method POST. We will also attach our startFrom variable with the AJAX object (line 45). When the response is successfully received from the server (line 15), it will be in a JSON string. So we convert that into Javascript arrays and objects (line 20). Then we are appending the newly fetched data in our tbody tag. And finally, we are incrementing the startFrom variable with the number of records we want to show in each AJAX call.

// This function will be called every time a button pressed 
function getData() {
    // Creating a built-in AJAX object
    var ajax = new XMLHttpRequest();

    // tell the method and URL of request
    ajax.open("POST", "http://localhost:3000/load-more", true);

    // Detecting request state change
    ajax.onreadystatechange = function () {

        // Called when the response is successfully received
        if (this.readyState == 4) {

            if (this.status == 200) {
                // For debugging purpose only
                // console.log(this.responseText);

                // Converting JSON string to Javasript array
                var data = JSON.parse(this.responseText);
                var html = "";
         
                // Appending all returned data in a variable called html
                for (var a = 0; a < data.length; a++) {
                    html += "<tr>";
                        html += "<td>" + data[a]._id + "</td>";
                        html += "<td>" + data[a].name + "</td>";
                        html += "<td>" + data[a].age + "</td>";
                    html += "</tr>";
                }
         
                // Appending the data below old data in <tbody> tag
                document.getElementById("data").innerHTML += html;

                // number of records you want to show per page
                var limit = 2;
         
                // Incrementing the offset so you can get next records when that button is clicked
                startFrom = startFrom + limit;
            }
        }
    };

    var formData = new FormData();
    formData.append("startFrom", startFrom);

    // Actually sending the request
    ajax.send(formData);
}

Now we need to create a POST route in our server.js. Before creating a POST route, we need to tell our Express app that we will be using the Express-Formidable module to get values (e.g. startFrom) from AJAX requests. So paste the following lines before starting HTTP server:

// server.js

// used to get POST field values
var formidable = require("express-formidable");
app.use(formidable());

Now write the following lines after the Mongo DB is connected:

// create a POST HTTP route to get data
app.post("/load-more", async function (request, result) {
 
    // number of records you want to show per page
    var limit = 2;
 
    // get records to skip
    var startFrom = parseInt(request.fields.startFrom);
 
    // get data from mongo DB
    var users = await database.collection("users").find({})
        .sort({ "id": -1 })
        .skip(startFrom)
        .limit(limit)
        .toArray();
 
    // send the response back as JSON
    result.json(users);
});

If you run the code now, you will see 2 records when the page loads. On clicking the load more button, 2 more records will be fetched, and so on.

Styling the table – CSS

At this point, you have successfully created a feature where you can display a few records when the page loads. And further records when user clicks a “load more” button. But we can give a few styles just to make it look good. The following styles will:

  • Give 1-pixel black border to the table and all its headings and data tags.
  • border-collapse will merge all the borders into one.
  • We are giving padding (distance between border and content) to all headings and data tags.
  • Give some margin from the bottom to the table to have some space between the table and load more button.
table, th, td {
    border: 1px solid black;
    border-collapse: collapse;
}
th, td {
    padding: 25px;
}
table {
    margin-bottom: 20px;
}

Now that our load more Node JS button is fully functional. We can also try another approach that is usually called “Infinite scroll”.

Infinite scroll

You can also use an “infinite scroll” like Facebook. Instead of displaying a button to load more data, more data will be fetched when the user scrolled to the bottom. No need to change the Node JS code that we used to load more button. For that, first you need to include jQuery.

<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script>

Then you can replace your window onload event listener with the following:

var loadMore = true;

window.addEventListener("load", function () {
    // Calling the function on page load
    getData();

    $(window).bind('scroll', function() {
        if(!loadMore && $(window).scrollTop() >= $('#data').offset().top + $('#data').outerHeight() - window.innerHeight) {
            // console.log('end reached');
            loadMore = true;
            getData();
        }
    });
});

And finally in your ajax.onreadystatechange listener, when you successfully append the data in the <tbody> tag, keep the infinite scroll working if there are more records.

if (data.length > 0) {
    loadMore = false;
}

So that’s how you can create a load more Node JS button with Mongo DB.

[wpdm_package id=’1251′]