Yohanes Mario [dot] com

my online scrapbook of scrambled thoughts

JavaScript is a confusing language. You can do OOP with it, you can do functional programming with it, and so on. A typical and modern way of encapsulating things in javascript is by creating an object. Objects in javascript are defined by a JSON notation (a single object throughout the runtime) or by creating what's known as a constructor function:

function Creature(legs) {
    this.legs = legs; // This is a public attribute

    this.speak = function(){ // This is a public method
        console.log("Hi!");
    };
}

var person = new Creature(2);
person.speak(); // console: Hi!

However, you don't have private or public modifiers in javascript. Everything added to this will result as a public member of that object. So, how do we create private members? The answer: closure. Closure is a concept in javascript which states that anything defined inside a closure (those curly braces) will stay inside it. Nothing from outside of the closure can access anything that's defined inside of the closure. So, we can make:

function Creature(legs) {
    this.legs = legs; // This is a public attribute
    var sound = "Hi!"; // This is a private attribute
    
    var makeSound = function(){ //This is a private method
        console.log(sound);
    };

    this.speak = function(){ // This is a public method
        makeSound();
    };
}

var person = new Creature(2);
person.speak(); // console: Hi!

I exploited this behavior to make sure that no one can mess with the internal states of my web applications by doing this:

$(document).ready(function(){
    // The rest of your code goes here
});

That way, no external javascript can mess with my internal states. The lesson is, never define your application states as globals, always use closure, be it in an object, or as simple as inside of an initial function. As always, happy blogging!

   Posted in Web        Yohanes Mario Chandra        0 Comments

While trying to create a simple web-based desk clock, I notice that not all computers are made equal in regards to the way they sync time. Since then, I've been trying to create a simple HTTP and JSON based ntp server to sync all of my clocks. The result is as follows:

var start = (new Date()).getTime();
$.ajax({
    url: 'http://time.yohanesmario.com/ntp',
    type: "GET",
    cache: false,
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    success: function(data) {
        var end = (new Date()).getTime();
        var responseTime = end-start;
        if (data!=null && data.milliseconds_since_epoch!=null) {
            var time = parseInt(data.milliseconds_since_epoch);
            
            // Calibrate ntp time
            time = time + (responseTime/2);
            
            // Calculate offset
            offset = end-time;
        }
    }
});

Notice that I add half of the response time to the time obtained from the NTP. This is because HTTP as a protocol consist of 2 part, request and response, each took half of the total time. And then, there is TLS.

TLS (more widely known as SSL or HTTPS) works very differently. It, under normal circumstances (TLS 1.2), took 2 round trip handshake before the actual HTTP protocol begin. So, in total, it took 3 round trip to complete an HTTPS request. That's why, the actual time it took for the HTTP response to actually reach the client is responseTime/6. We change our original code accordingly:

var start = (new Date()).getTime();
$.ajax({
    url: 'https://time.yohanesmario.com/ntp',
    type: "GET",
    cache: false,
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    success: function(data) {
        var end = (new Date()).getTime();
        var responseTime = end-start;
        if (data!=null && data.milliseconds_since_epoch!=null) {
            var time = parseInt(data.milliseconds_since_epoch);
            
            // Calibrate ntp time
            time = time + (responseTime/6);
            
            // Calculate offset
            offset = end-time;
        }
    }
});

This may help you, or may not. Either way, happy blogging!

   Posted in Web        Yohanes Mario Chandra        0 Comments

Making a drawing pad with HTML 5 canvas element is relatively easy, until we encounter touch devices. The codes which used to be working on conventional mouse-driven interface no longger works on touch screens. The purpose of making a drawing pad with the canvas element was simple: to facilitate people to draw from anywhere (as long as they have internet and a browser). But what's more pleasing than drawing on touch enabled screens?

Actually, it's not that hard to make a touch compatible canvas. It's almost the same as the mouse driven code, but with some changes. I'll let you see for yourself. Here's a code I get from http://tenderlovingcode.com/static/download/draw.html:

<!DOCTYPE html> 
<head> 
    <meta charset="utf-8"> 
    <meta name="viewport"
        content="width=768px, maximum-scale=1.0" /> 
    <title>sketchpad</title> 
    <script type="text/javascript" charset="utf-8"> 
    window.addEventListener('load',function(){
        // get the canvas element and its context
        var canvas = document.getElementById('sketchpad');
        var context = canvas.getContext('2d');
        
        // create a drawer which tracks touch movements
        var drawer = {
            isDrawing: false,
            touchstart: function(coors){
                context.beginPath();
                context.moveTo(coors.x, coors.y);
                this.isDrawing = true;
            },
            touchmove: function(coors){
                if (this.isDrawing) {
                    context.lineTo(coors.x, coors.y);
                    context.stroke();
                }
            },
            touchend: function(coors){
                if (this.isDrawing) {
                    this.touchmove(coors);
                    this.isDrawing = false;
                }
            }
        };
        // create a function to pass touch events
        // and coordinates to drawer
        function draw(event){
            // get the touch coordinates
            var coors = {
                x: event.targetTouches[0].pageX,
                y: event.targetTouches[0].pageY
            };
            // pass the coordinates to the appropriate handler
            drawer[event.type](coors);
        }
        
        // attach the touchstart, touchmove, touchend event listeners.
        canvas.addEventListener('touchstart',draw, false);
        canvas.addEventListener('touchmove',draw, false);
        canvas.addEventListener('touchend',draw, false);
        
        // prevent elastic scrolling
        document.body.addEventListener('touchmove',function(event){
            event.preventDefault();
        },false);	// end body.onTouchMove
        
    },false);	// end window.onLoad
    </script> 
    <style type="text/css"></style> 
</head> 
<body> 
    <div id="container"> 
        <canvas id="sketchpad" width="766" height="944">
            Sorry, your browser is not supported.
        </canvas>
    </div> 
</body>
</html>

You can see that instead of mouseOver, mouseMove and mouseOut events, it uses touchstart, touchmove and touchend events. It is nearly as simple as that, with addition of the script which disable iOS's elastic scrolling. This code is proven to be working on Android devices too.

   Posted in Web        Yohanes Mario Chandra        0 Comments