lørdag 19. mars 2016

Double pointed arrows in HTML5 canvas


Drawing things like arrows might be hard in canvas, because there is no predefined function we can use. However with some trigonometry, this is not at all an exhausting task, but a bit complicated, especially when we are going to make the arrow double ended.


The arrow system is based upon this principle (and a bit trying and failing):




Based on that, I made the following JavaScript/HTML5 code:



<canvas id="arrows" height="500px" width="1000px"></canvas>

<script>

var canvas=document.getElementById("arrows");

var ctx=canvas.getContext("2d");

function draw_arrows(startX, startY, endX, endY, angle, width, length, color, ctx){

//The angle between the arrow and the canvas' x-axis. 
//Multiplied by 180/π for converting from radians to degrees.

 var main_angle=Math.atan2(startY-endY,startX-endX)*(180/Math.PI);

//Offsetting the given angle into the angle in the coordinate system of the canvas. 
//Multiplied with π/180 for converting back to radians, because that's what JavaScript uses.
 
 var offsetted_angle1=(main_angle+angle)*(Math.PI/180);
 
//We need to different angles, because the points of the arrows have different angles
//compared to the coordinate system.
 
 var offsetted_angle2=(main_angle-angle)*(Math.PI/180);
 
//Find the length of arrow on x-axis by using cosine.
 
 var xlength1=length*Math.cos(offsetted_angle1);
 
 var ylength1=length*Math.sin(offsetted_angle1);
 
 var xlength2=length*Math.cos(offsetted_angle2);
 
 var ylength2=length*Math.sin(offsetted_angle2);
 
 ctx.beginPath();
 
 var arrowX=startX-xlength1;
 
 var arrowY=startY-ylength1;

 ctx.moveTo(arrowX,arrowY);
 
 ctx.lineTo(startX,startY);
 
 arrowX=startX-xlength2;
 
 arrowY=startY-ylength2;
 
 ctx.lineTo(arrowX,arrowY);
 
 ctx.moveTo(startX,startY);
 
 ctx.lineTo(endX,endY);
 
//Reverse length on the other side
 
 arrowX=endX+xlength1;
 
 arrowY=endY+ylength1;
 
 ctx.moveTo(arrowX,arrowY);
 
 ctx.lineTo(endX,endY);
  
 arrowX=endX+xlength2;
 
 arrowY=endY+ylength2;
 
 ctx.lineTo(arrowX,arrowY);
 
 ctx.strokeStyle=color;
    
 ctx.lineWidth = width;
 
 ctx.stroke();
}

</script>



You can see a demonstration of the code below:



If there are any questions or suggestions of things I could have done better, please use comment section below.

onsdag 24. februar 2016

Node.js, Express and Mongodb beginner tutorial; make a simple comment site. | Part 3: Register and show comments

This is a continuation of a tutorial. If you have not finished step 1 and 2, do that first: http://allrounddeveloper.blogspot.no/2016/02/nodejs-express-and-mongodb-beginner.html


Step 5 – Setup for comments

The final part is to make the users able to comment. For this too, I start with the jade file, but this one is a bit more complicated. This is the comments.jade file:


doctype html
html
    head
        title Comments
        meta(charset="utf-8")
        link(rel="stylesheet",href="stylesheets/style.css")
    body
        h1 Comments
        each comment, i in comments
            table
                tr
                    th=comment.username
                    th=comment.date
                tr
                    td(colspan="2")=comment.comment
        if loggedin
            h2 Comment in the field below.
            form(method="post",action="/submit")
                textarea(name="comment")
                br
                input(type="submit",value="Submit comment")
        else
            p You have to be logged in to comment.
            br
            a(href="/login") Log in.
            br
            a(href="/signup") Sign up.
 


We can send arrays or variables with information to the jade file. In this case, we send the comments array into the jade engine.


The jade file says that for every comment in the array, the jade engine would fill in the username, date and content of the comment. "For each" is for doing something with every instance in an array. We use an equals sign to set the content of an HTML-tag to a variable.


We also use an if-statement, which means that if the bool is true the jade engine outputs the tags that is nested beneath. We have an else statement with some other content. We send a bool that tells jade engine whether the user is logged in.


We need node.js to send the comments to the jade engine, when the user is on the front page.


app.get("/",function(req, res) {

    MongoClient.connect("mongodb://localhost:27017/admin",function (err, db) {

        if (err) {

            console.log('Unable to connect to the mongoDB server. Error:'+ err);


        else {

            console.log('Connection established to mongodb://localhost:27017/admin');

            var users=db.collection("users");

            var comments=db.collection("comments"); 

//new collection where we store the comments

            var loggedin;

//a variable that checks whether the user is logged in

            if (req.cookies.session_id==""){ 

//if the user has no session_id cookie, the user is not logged in. req.cookies.cookie_name finds the value for a given cookie from the user.

                loggedin=false;

            }

            else{

                users.findOne({"session_id": to_hash("Another random salt"+req.cookies.session_id+"Randomed hash")},function(e,docs){ 


//check if an user actually has the hash value from the session_id

                    if(e) throw e;

                    if (docs==null){

                        loggedin=false;

                    }

                    else{

                        loggedin=true;

                    }

                });

            }

            comments.find({}).sort({"date":-1}).toArray(function(e,com){ 

//comments.find finds all the comments in the database. The sort command says that mongodb shall sort the comments in a descending order, from newest to oldest. ToArray function makes the result to a function, stored in the variable “com”.

                res.render("comments",{ 

//this is the way we send variables to the jade engine. “comments” in the jade file is given the variable “com” from node.js.

                "comments":com,

                "loggedin":loggedin

                });

                db.close();

            });
        }
    });
});


The only thing left now is to register the comments that is sent. I sent the post requests to “/submit”.


Here is the node.js code:


app.post("/submit",function(req, res) {

    if (req.body.comment==""){

        req.send("Sorry, you cannot have an empty comment.");

    }

    else if (req.cookies.session_id==""){

        res.send("You have to be logged in to comment.");

    }

    else{

        MongoClient.connect("mongodb://localhost:27017/admin", function (err, db) {

            if (err) {

                console.log('Unable to connect to the mongoDB server. Error:'+ err);

            }
            else {

                console.log('Connection established to mongodb://localhost:27017/admin');

                var users=db.collection("users");

                var comments=db.collection("comments");

                users.findOne({"session_id": to_hash("Another random salt"+req.cookies.session_id+"Randomed hash")},function(e,docs){

                    if(e) throw e;

                    if (docs==null){

//if no user is found with the cookie, the login is not valid.

                        res.send("Your login is not valid.");

                        db.close();

                    }

                    else{

                        comments.insert({"comment":req.body.comment,"username":docs.username,"date":new Date()},function(err,result){

//the date variable saves the date when the comment is submitted.

                            if (err) throw err;

                            res.send("Comment saved.");

                            db.close();

                        });
                    }
                });
            }
        });
    }  
});


All my project files can be found here: https://www.dropbox.com/sh/vaqnof1ebejb31j/AABGmy_AQPS3IIaWLo7PEAoSa?dl=0


If there are any questions or suggestions of things I could have done better, please use comment section below.


tirsdag 23. februar 2016

Node.js, Express and Mongodb beginner tutorial; make a simple comment site. | Part 2: Sign Up and Log In with jade


This is a continuation of a tutorial. If you have not finished step 1, do that first: http://allrounddeveloper.blogspot.no/2016/02/nodejs-express-and-mongodb-beginner.html


Step 3 – Sign up page


I chose to make the signup page first, because you need content before you can show it, and the point is that you have to be logged in to comment.


As I mentioned before I use the jade engine, which can generate HTML pages. I think jade is both simpler and faster to write than normal HTML. For the signup page, open the views folder and make an empty file called signup.jade.


This is my signup.jade file:


doctype html
    html
        head
            title Sign Up
            link(rel="stylesheet", href="/stylesheets/style.css")
        body
	    h1 Sign Up
            form(method="post")
                input(name="username", placeholder="Username", type="text")
                br
                input(name="password", placeholder="Password", type="password")
                br
                input(value="Sign Up", type="submit")
            br
            br
            a(href="/login") Log in


The format is (in my opinon) not very hard to understand. Instead of having xml tags inside each other, like you do in HTML, you nest tags inside each other by using indents (the tab button).


You start every line with the tag you want to use. Afterwards, you could have a parenthesis. Inside the parenthesis, you can set attributes like those that I have done over. If you want content inside the tags, you just do like what I have done inside the title tag. Just a space and then the content inside the tag.


As you may remember, you have static files inside the public folder, like the stylesheets/style.css. I use this file as my CSS file. You can set up the CSS to get the design you want. (you will probably change it as it is not very nice):



html{
font-family:Arial;
text-align:center;
background-color:gray;
}
div {
margin:auto;
}
table {
    border-collapse: collapse;
    margin:auto;
    width:40%;
}

table, th, td {
    border: 1px solid black;
    text-align:center;
}
textarea{
  width:40%;
  margin:auto;
}


Now that the signup page is ready, we have to say to the node.js that this is the page that we open when someone go to “/signup”. Therefore add the following to the app.js file before the error message functions:



app.get("/signup",function(req, res) {
    res.render("signup");
});


This function says that when someone is going to the “yourapp.com/signup”, the web app shall send the signup.jade file as an HTML file to the user.


app.get means that when someone is sending a GET-request to the site, this is what is going to happen.


Parameter req, is short for request and includes information about the user’s request, like his/her cookies and IP-address.


Parameter res, is short for respond and is what the web app send back to the user.


What is much harder is to register the user in the database. Here is what I did:


//First of all I made a function that hashes passwords:

function to_hash(pass){ 

//takes the argument pass that is what is going to be hashed


  return crypto.createHash("sha256").update(pass).digest("base64"); 

//this uses the crypto add-on to make hashes out of the password. createHash takes the hashing method as argument. The update method tells what is going to be hashed, and the digest menthod tells what format the output should be in.

}


app.post("/signup",function(req,res){ 

//app.post because this is a post request.


    if (req.body.username=="" || req.body.password==""){ 

//req.body.variable gets the variables that is sent through the HTML.


        req.send("Sorry, invalid username and/or password"); 

//Because you cannot have a empty username or password.
    
    }
    else
    {
        MongoClient.connect("mongodb://localhost:27017/admin",function (err, db) { 

//This connects to the mongodb. “mongo://localhost:27017/” is the standard URL for mongodb and “/admin” is the database inside mongodb we want to connect to.

            if (err) {
                console.log('Unable to connect to the mongoDB server. Error:'+ err); 

//If something goes wrong, we see that inside the logs.

            } 
            else
            {
                console.log('Connection established to mongodb://localhost:27017/admin');
                var users=db.collection("users"); 

//this connects to a collection inside node.js. This is the about the same as a table in SQL-databases.

                users.findOne({"username":req.body.username},function(e,doc){ 

//check if there are someone who has already registered the username in the users collections. Doc is the result that is sent back from the query.

                    if (doc==null){ 

//if no one has the username, you are free to register.

                        users.insert({"username":req.body.username,"password":to_hash("Random salt"+ req.body.password+"Other random salt")},function (err, result) { 

//users.insert insert a new instance into a collection. Change the salts into other strings, because the salts are secret, otherwise hackers can crack the passwords.

                            if (err){
                                    console.log(err); 

//log the error if any.

                                    res.send("Sorry, server error."); 

//tell the user if there is an error with the request.

                            }
                            else
                            {
                                res.send("Success"); 

//tell that the user successfully registered the user account.

                                db.close(); 

//close connection with the database as you no longer need it.

                             }
                         });
                        }
                     else
                     {
                         res.send("Sorry, username already taken."); 

//if the username was already taken, tell the user.


                         db.close();
                     }
                 });
             }
         });
     }
});


Now you need two terminals to check if everything is working.


One where you start mongodb (it has to be running if mongodb requests shall work):


C:\ > mongod


And another that is set inside your node.js app directory:


C:\nodeapp\testapp> npm start


Go to http://localhost:3000/signup and try if it is working-


Hopefully, you can register and get the result “success”.


To be sure  that everything works you shold be able to see a logs in the terminal window where you started mongodb. If everything went fine you would get a result like this:



2016-02-23T14:54:29.698+0000 [initandlisten] connection accepted from 127.0.0.1:59804 #1 (1 connection now open)
2016-02-23T14:54:29.722+0000 [initandlisten] connection accepted from 127.0.0.1:59806 #2 (2 connections now open)

2016-02-23T14:54:29.728+0000 [conn1] end connection 127.0.0.1:59804 (1 connection now open)
2016-02-23T14:54:29.744+0000 [conn2] allocating new ns file /data/db/admin.ns, filling with zeroes...
2016-02-23T14:54:29.825+0000 [FileAllocator] allocating new datafile /data/db/admin.0, filling with zeroes...
2016-02-23T14:54:29.825+0000 [FileAllocator] creating directory /data/db/_tmp
2016-02-23T14:54:29.834+0000 [FileAllocator] done allocating datafile /data/db/admin.0, size: 64MB,  took 0.002 secs
2016-02-23T14:54:29.836+0000 [conn2] build index on: admin.users properties: { v: 1, key: { _id: 1 }, name: "_id_", ns: "admin.users" }
2016-02-23T14:54:29.836+0000 [conn2]     added index to empty collection
2016-02-23T14:54:29.843+0000 [conn2] end connection 127.0.0.1:59806 (0 connections now open)


This says that mongodb made a new collection for your request and that the user is added.


Step 4 – Login Page


For a login page, you need a new jade file where you can log in, like this one (call it “login.jade”, still in the views folder):



doctype html
    html
        head
            title Log In
            link(rel="stylesheet", href="/stylesheets/style.css")
        body
	    h1 Log In
            form(method="post")
                input(name="username", placeholder="Username", type="text")
                br												input(name="password", placeholder="Password", type="password")
                br
                input(value="Log In", type="submit")
	    br
	    br
	    a(href="/signup") Sign Up


You have to tell node.js that it is this page it is going to show, when people enter the “/login” URL:



app.get("/login",function(req,res){
  res.render("login");
});


And as before, this is the easy part. To check if the login is valid, you can use the following code. Fortunately, the concepts are basically the same:



function random_string(){ 

//we check whether a user is logged in, by checking his/her cookies. To prevent anyone from using another person’s hash in the cookies, we have to give people random hashes.

    return crypto.randomBytes(139).toString('base64');

//the randomBytes function makes random bytes than can be transformed to a string. The randomBytes function takes a parameter that tells how many bytes that is going to be made. 139 is more than enough.

}


app.post("/login",function(req,res){

    MongoClient.connect("mongodb://localhost:27017/admin",function (err, db) {

        if (err) {

           console.log('Unable to connect to the mongoDB server. Error:' + err);

        }

        else

        {

            console.log('Connection established to mongodb://localhost:27017/admin');

            var users=db.collection("users");

            users.findOne({"username":req.body.username},function(e,docs){

//check if there are users with the  username that is given

               if(e) throw e;

//An other way to log errors.

               if (docs==null){

//if there are  no users with username, tell the user so.

                   res.send("No user with that username.");

                   db.close();

               }

               else if (docs.password== to_hash("Random salt"+ req.body.password+"Other random salt")){


//if the password the user gave, is the same as the one he/she gave upon signup, the two hash values are the same.

                   var session_id=random_string();

                   res.cookie("session_id",session_id);

//this gives the user a random string in the cookies, that proves that he/she is logged in.

                   users.update({"username":docs.username},{$set:{"session_id":to_hash("Another random salt"+session_id+"Randomed hash")}},function(err,result){

//we crypt the session_id so that hackers cannot pretend to be users if they get control over the database.

                       if (err) throw err;

                       db.close();

                       res.write("success");

//tell user if login is successful.

                       res.end();
                   });
               }
               else{

                   res.send("Wrong username or password");

//tell user if password or username is wrong.

                   db.close();
               }
           });
       }
   });
});


Test if this work the same way as you checked whether the signup page worked.
The login page is at http://localhost:3000/login


If it works:


Congrats! You have a working user validation system.


You can now go on to part 3 of the tutorial: http://allrounddeveloper.blogspot.no/2016/02/nodejs-express-and-mongodb-beginner_24.html


If there are any questions or suggestions of things I could have done better, please use comment section below.

Node.js, Express and Mongodb beginner tutorial; make a simple comment site. | Part 1: Set up node.js and mongodb



If you have not already, install node.js from this site: https://nodejs.org/en/download/


You also need mongodb to do this tutorial: https://www.mongodb.org/downloads


Step 1 – Set up a node.js workspace with express


1. First, you have to make a directory for your new app, like C:\nodeapp. You can either do this in Windows Explorer or through command line.


In Windows Explorer you just have to make the folder you want to have your app inside.


Through command line (cmd.exe in Windows), you could use this command:


C:\> mkdir nodeapp


2. You have to point the command line to the folder where you keep your project:


C:\> cd nodeapp
C:\nodeapp>


3. You have to install all the dependencies that we need in this app. The most important one is express, which is an add-on to node.js that makes it much easier to select what is on different places on your website. It also makes a template for a node app, so you do not have to make all the files you need yourself. Installing dependencies for node.js is done through something called npm (= node package manager). (The –g in the command says that the express-generator shall auto-install).  You install express through command line this way:


C:\nodeapp> npm install -g express-generator


4. Use the express-generator to make a template for your app, where you change “testapp” with the name you want to use for your app:  
                                                                                    

C:\nodeapp> express testapp


If everything goes well you end up with a document structure like this:


                                                         


I will explain some of the files later.


5. You have to install all the dependencies that your new app needs. Do this in the terminal:


C:\nodeapp> cd testapp
C:\nodeapp\testapp> npm install


You can test if everything went fine by starting the app. To start your current app you have to start it through command line:


C:\nodeapp> cd testapp
C:\nodeapp\testapp> npm start


The terminal will now output something like:


> testapp@0.0.0 start /home/ubuntu/workspace/node/testapp
> node ./bin/www


The app is now started, and you can try it through localhost: http://localhost:3000


If everything went fine, you would see the following in your browser:





To stop your app again, go back to your terminal and press Ctrl+C. Congrats, you have set up a node.js workspace!


Step 2 – Set up a mongodb database


The main file of every node.js app is called “package.json”. This is a json file, which means that it has a special structure. Json is a file format where you can store data in columns, and is the format that mongodb use to store data. Your “package.json” probably looks like this:


{
  "name": "testapp",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "body-parser": "~1.13.2",
    "cookie-parser": "~1.3.5",
    "debug": "~2.2.0",
    "express": "~4.13.1",
    "jade": "~1.11.0",
    "morgan": "~1.6.1",
    "serve-favicon": "~2.3.0"
  }
} 


First on every line with data, you have a string that is the name of the variable, then comes a colon, and afterward is the value of the variable. The first important value here is "scripts", which has the variable "start". The value of "start" says which script is the main script. The main script is "node ./bin/www", which is a server script. The script basically starts a server, and sends all the requests to your "app.js" script, and that is where I write most of the code.


What is also important in the "package.json" file is the "dependencies" category. The category lists everything we need to get the app running. As you see, the express add-on is successfully implemented. However, we miss the mongodb add-on that is necessary to get the app communicate with the database.


For security reasons, when people register their username and password, it is usual to hash the password. Hashing is a one-way encrypting algorithm, which cannot be done back again. Therefore, even if hackers get control over our database, they will not be able to get the passwords. To being able to hash passwords in node.js, you have to have the additional crypto add-on.


To install the mongodb and crypto dependencies, use the terminal again:


C:\nodeapp\testapp> npm install mongodb --save
C:\nodeapp\testapp> npm install crypto --save


The --save part in the end of the line tells npm that it should update the "package.json" file with mongodb and crypto as new dependencies. If you refresh your "package.json" file both mongodb and crypto should be listed:


{
  "name": "testapp",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "node ./bin/www"
  },
  "dependencies": {
    "body-parser": "~1.13.2",
    "cookie-parser": "~1.3.5",
    "crypto": "0.0.3",
    "debug": "~2.2.0",
    "express": "~4.13.1",
    "jade": "~1.11.0",
    "mongodb": "^2.1.7",
    "morgan": "~1.6.1",
    "serve-favicon": "~2.3.0"
  }
}


The mongodb is now installed!


However, you also need to update the require list in the app.js file. Open the app.js file and you would see that the first lines is probably something like this: Open the app.js file, and look at the requires in the start:


var express = require('express');
var path = require('path');
var favicon = require('serve-favicon');
var logger = require('morgan');
var cookieParser = require('cookie-parser');
var bodyParser = require('body-parser');




Our node.js app does also require mongodb and crypto in order to work, therefore add the
following lines:


var crypto=require("crypto");
var mongodb = require('mongodb');
var MongoClient = mongodb.MongoClient;


The mongodb.MongoClient line is because you need the MongoClient part of the mongodb add-on to connect and send requests to the mongo database.


Step 3 – Setting up the app.js file


I want for simplicity, have the whole app inside the "app.js" file. Therefore you don’t need the routes folder or the files in the folder. You can therefore delete the next following lines:


var routes = require('./routes/index');
var users = require('./routes/users');


The next lines are necessary. This is what they do:


var app = express();


This means that this web application is a express app. The variable app will now get all the requests to the website.


// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'jade');


The next two lines says that we are using the jade engine to make HTML pages, and that the jade files is in the views folder. If you look inside the views folder, there are some .jade files there. I will explain the jade engine later.


// uncomment after placing your favicon in /public
//app.use(favicon(path.join(__dirname, 'public', 'favicon.ico')));


If you put an favicon.ico file in the public folder, you can remove the comment slashes from the second line. The line is just for inserting a icon on your web page.


app.use(logger('dev'));


This line says that the web application shall make a log of what is happening on the app. This will make it easier to see what eventual errors are, but is not necessary for the app to work. I would, however, recommend that you keep it.


app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));


This is for getting parameters like username or comments that the users are submitting to the page.


app.use(cookieParser());


We use this so that we can read the users' cookies. This is necessary, because we use the cookies to see whether someone is logged in.


app.use(express.static(path.join(__dirname, 'public')));


This line says that everything inside the public folder are static files, which means that if someone go into the URL of these files, they are getting the plain file. This is useful for having a place to store CSS or client-side JavaScript files.


app.use('/', routes);
app.use('/users', users);


You should delete the lines over, because I am going to have the whole app inside “app.js”. Anyway, what the lines do is that if you get a get request to the sites “/” or “/users”, the request is forwarded to the index.js or the users.js file. To divide the web application like this makes larger applications more structured, but for small web applications it is easier to just use the “app.js” file.


The rest of the lines beneath are just the error messages that your web application will show when there are errors. It is not very important, but keep them as they show the errors in your web application when they occur.


You can now continue on part two on the project: http://allrounddeveloper.blogspot.no/2016/02/nodejs-express-and-mongodb-beginner_23.html


If there are any questions or suggestions of things I could have done better, please use comment section below.