4
\$\begingroup\$

I am doing some tests with html5 Canvas object. At the same time I am trying to make my javascript code more modular. In the following code, where/how should I declare canvas and context, so that it can be shared with other objects? Please provide general comments/improvements?

Output:

enter image description here

Code:

$( document ).ready(function() {

    var axis = {
        LEFT_INDENT : 100,  
        START_WORK_HOUR : 8,
        END_WORK_HOUR : 17,
        HOURS_IN_WORKDAY : 0,
        CANVAS_WIDTH : 0,
        CANVAS_HEIGHT : 0,
        AXIS_SIDE_MARGIN : 20,
        AXIS_TOP_MARGIN : 40,
        AXIS_ORIGIN : new Array(),  
        AXIS_RIGHT : 0,
        TICK_INCREMENT :  0,

        setup: function(){

            // assumes that I have <canvas id="myCanvas" width="800" height="300"></canvas>  in the HTML
            this.canvas = document.getElementById('myCanvas');
            this.context = this.canvas.getContext('2d');

            this.HOURS_IN_WORKDAY = this.END_WORK_HOUR - this.START_WORK_HOUR;
            this.CANVAS_WIDTH = this.canvas.width;
            this.CANVAS_HEIGHT = this.canvas.height;

            this.AXIS_ORIGIN = { x: this.AXIS_SIDE_MARGIN,
                            y: this.AXIS_TOP_MARGIN };

            this.AXIS_RIGHT = this.canvas.width-this.AXIS_SIDE_MARGIN;

            this.TICK_INCREMENT = (this.CANVAS_WIDTH-this.LEFT_INDENT-(2*this.AXIS_SIDE_MARGIN))/this.HOURS_IN_WORKDAY; 
            this.AXIS_RIGHT = this.canvas.width-this.AXIS_SIDE_MARGIN;
        },

        draw_lines: function(){
            this.context.beginPath();
            this.context.moveTo(this.LEFT_INDENT, this.AXIS_ORIGIN.y);
            this.context.lineTo(this.AXIS_RIGHT,  this.AXIS_ORIGIN.y)
            this.context.stroke();
            this.counter = this.START_WORK_HOUR;

            for(x=this.AXIS_SIDE_MARGIN+this.LEFT_INDENT ; x < this.AXIS_RIGHT ; x = x + this.TICK_INCREMENT){
                // grid lines
                this.context.beginPath();
                this.context.moveTo(x,30);
                this.context.lineTo(x,50)
                this.context.stroke();

                // background line - top to bottom
                this.context.save();   
                this.context.fillStyle = "#F0F8FF";
                this.context.beginPath();
                this.context.lineWidth = .1;
                this.context.moveTo(x,30);
                this.context.lineTo(x,this.CANVAS_HEIGHT-20)
                this.context.stroke();
                this.context.restore();   

                // text     
                this.context.font = "14px Arial";
                this.context.fillStyle = "#011f5b";     
                this.counter++;
                this.context.fillText(this.counter+":00",x-7,20);       
            }   
        }
    }
    axis.setup();
    axis.draw_lines();
});
\$\endgroup\$
1
  • \$\begingroup\$ I'm not sure this will be helpful, but I created a github project called brushes.js which somewhat tries to encapsulate brushes to draw on a canvas. There are unit tests and examples. \$\endgroup\$
    – Jim Schubert
    Jul 5, 2013 at 6:33

1 Answer 1

2
\$\begingroup\$

You can wrap the functionality in an object. You instantiate it with a canvas element and some configuration options.

(function($) {

// config defaults    
var defaults = {
    LEFT_INDENT: 100,
    START_WORK_HOUR: 8,
    END_WORK_HOUR: 17,
    AXIS_SIDE_MARGIN: 20,
    AXIS_TOP_MARGIN: 40
};

// constructor
axis = function(canvas, config)
{
    this.config = $.extend({}, defaults, config);
    this.canvas = canvas;

    this.setup();
}

// define prototype functions
axis.prototype.setup = function() {
    this.context = this.canvas.getContext('2d');

    this.HOURS_IN_WORKDAY = this.config.END_WORK_HOUR - this.config.START_WORK_HOUR;
    this.CANVAS_WIDTH = this.canvas.width;
    this.CANVAS_HEIGHT = this.canvas.height;

    this.AXIS_ORIGIN = {
        x: this.config.AXIS_SIDE_MARGIN,
        y: this.config.AXIS_TOP_MARGIN
    };

    this.AXIS_RIGHT = this.canvas.width - this.config.AXIS_SIDE_MARGIN;

    this.TICK_INCREMENT = (this.CANVAS_WIDTH - this.config.LEFT_INDENT - 2*this.config.AXIS_SIDE_MARGIN)) / this.HOURS_IN_WORKDAY;
}

axis.prototype.draw_lines = function() {
    this.context.beginPath();
    this.context.moveTo(this.LEFT_INDENT, this.AXIS_ORIGIN.y);
    this.context.lineTo(this.AXIS_RIGHT,  this.AXIS_ORIGIN.y)
    this.context.stroke();
    this.counter = this.config.START_WORK_HOUR;

    for(x = this.config.AXIS_SIDE_MARGIN + this.config.LEFT_INDENT ; x < this.AXIS_RIGHT ; x = x + this.TICK_INCREMENT) {
        // grid lines
        this.context.beginPath();
        this.context.moveTo(x,30);
        this.context.lineTo(x,50)
        this.context.stroke();

        // background line - top to bottom
        this.context.save();   
        this.context.fillStyle = "#F0F8FF";
        this.context.beginPath();
        this.context.lineWidth = .1;
        this.context.moveTo(x,30);
        this.context.lineTo(x, this.CANVAS_HEIGHT - 20)
        this.context.stroke();
        this.context.restore();   

        // text     
        this.context.font = "14px Arial";
        this.context.fillStyle = "#011f5b";     
        this.counter++;
        this.context.fillText(this.counter+":00",x-7,20);       
    }   
}

}(jQuery));

To use it:

var a = new axis(document.getElementById('myCanvas'), {
     // whatever you want to override
});
a.draw_lines();
\$\endgroup\$
2
  • \$\begingroup\$ my god, there are so many ways of doing things in javascript! If I understand you group variables in its own array. The "axis" methods and properties do not have to be wrapped and grouped together. You are instantiating the axis object with the "new" verb then run the constructor within the object. Code is a bit neater, and setup is done within the class. What other advantages does this way offer? \$\endgroup\$
    – Abe
    Jul 5, 2013 at 3:30
  • \$\begingroup\$ @Abe With the encapsulation, it also allows to have multiple axis objects which are tied to canvas objects. \$\endgroup\$
    – Jack
    Jul 5, 2013 at 6:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.