3

I'm trying to learn JavaScript, using an OO approach. This is my code:

/*global document, MouseEvent */
MouseEvent.prototype.mouseCoordinates = function () {
    return {
        'x' : this.pageX - this.target.offsetLeft,
        'y' : this.pageY - this.target.offsetTop
    };
};

(function () {
    var Pencil = function () {},
        Canvas = function () {
            this.element = document.getElementById('canvas');
            this.tool = new Pencil();

            this.element.addEventListener('click', this.tool.draw, false);
        },
        c;

    Pencil.prototype.draw = function (event) {
        var context = event.target.getContext('2d'),
            coordinates = event.mouseCoordinates();

        context.fillRect(coordinates.x, coordinates.y, 5, 5);
    };

    c = new Canvas();
}());

I'm trying to do something like MS Paint. So, I've created a Canvas object and a Pencil one. I am able to do it using a procedural approach but I don't want to. I don't want to use any library now, I'm just studying.

I've these questions:

  • Are there any good practice to register events? Should I register events using the object constructor?

  • My canvas object has a tool (pencil in this case) object. Conceptually it's not good. My canvas should not have a tool object. It must provides a surface to draw and that's it! But, it's there as a callback (click event). How could I solve this?

  • Every tool will have the same interface but different behaviours. Could I create interfaces using Javascript?

  • What else can I improve?

UPDATE:

(function () {
    var pencil = {
        draw : function (event) {
            var context = event.target.getContext('2d'),
                coordinates = event.mouseCoordinates();

                context.fillRect(coordinates.x, coordinates.y, 5, 5);
        }
    },
        currentTool = pencil,
        canvas = (function () {
            var object = {};
            object.element = document.getElementById('canvas');

            object.element.addEventListener('click', function (event) {
                currentTool.draw(event);
            }, false);

            return object;
        }());
}());

I've followed all the tips (thank you, I appreciate your help!). What do you think? Now I have a "global" currentTool variable. What do you think about it? Thanks.

Thank you.

thom
  • 51
  • 4
  • 1
    (1) To bind events, use `addEventListener`. What do you mean by "register events using the object constructor"? (2) Just define the `Pencil` instance as an independent object and not as an property of the `Canvas` instance. (3) That's a good question. Interfaces are not part of JavaScript but there may be a way to emulate them... – Šime Vidas Aug 11 '11 at 17:12
  • Sorry, I meant: "Where should i bind events?". Thank you. – thom Aug 11 '11 at 17:14
  • You're doing it right. Inside the `Canvas` constructor, you create a new CANVAS object, and then bind the click handler to it. That's OK. However, consider having a `canvasClicked` handler instead of directly binding to `pencil.draw`. Inside a `canvasClicked` handler you could establish what the user did (if there are multiple possibilities), and then call different functions ... – Šime Vidas Aug 11 '11 at 17:19
  • Btw, how many Canvas instances exist on your page? If only one, then a constructor function is not really needed, and you can just define an object (singleton) which represents the Canvas element. – Šime Vidas Aug 11 '11 at 17:22
  • There's just a canvas element. I'll read about JS singleton. Do you recommend any link? There are too much old and wrong information about JS. Thanks. – thom Aug 11 '11 at 17:24
  • Actually clicking on the canvas will draw (using the current tool). The interface is the same, the tools draw in different ways. Thanks. – thom Aug 11 '11 at 17:26
  • Just seach "javascript singleton" on StackOverflow. For instance: http://stackoverflow.com/questions/1479319/simplest-cleanest-way-to-implement-singleton-in-javascript – Šime Vidas Aug 11 '11 at 17:26
  • Then I recommend an independent `canvasDraw` function (as the click handler), which determines which tool is selected and calls the `draw` method of that tool. – Šime Vidas Aug 11 '11 at 17:29
  • Šime Vidas, can you take a look at my update? Thanks. – thom Aug 12 '11 at 18:27
  • Why do you put the reference to the CANVAS element inside `canvas.element` instead of inside `canvas` directly? – Šime Vidas Aug 12 '11 at 18:39
  • Actually my canvas is going to have more responsabilities. Thanks. – thom Aug 12 '11 at 19:03
  • Aha ok. Your code looks solid - I recommend this book if you want to learn about various patterns that are used in JavaScript: http://oreilly.com/catalog/9780596806767 – Šime Vidas Aug 12 '11 at 19:08

2 Answers2

0

I know you said you don't want to use library but I gotta recommend you look into source code in a good open source library such as jquery. If you want to seriously learn more, you should look at the code real good developers wrote and see how they did for what you just asked. As far as I can tell, that, except for keeping reading, is one of the best way of learning a programming language with good practice.

Tae-Sung Shin
  • 20,215
  • 33
  • 138
  • 240
0
  • It's kinda tricky to register events without any framework (capturing or bubbling phase is only the beginning of your problems), so here are answers on other questions

  • Your pencil tool can listen to the canvas events and, eventually,
    when someone dispatch a click on it, the pencil tool looks in the
    global object (singleton) if it's an active tool. If it is, you
    change the color of some appropiate pixels on the canvas.

  • There's no interface (as in php) in javascript, only prototypical
    behaviour. You can, howewer write an abstract class, which methods
    (in prototype namespace) will throw an exception "not implemented",
    forcing you to override them.

  • As for improvements, you will surely find yourself fighting with
    different browser's behaviour. That's why (well, that's not all)
    frameworks exist. As I can see, you like developpent in OO style, I
    can give you an advice to try MooTools or, a harder one, Google
    Closure framework. Feel free to ask questions about them here.

Mironor
  • 1,157
  • 10
  • 25
  • About Framework I agree and I use them. They solves lots of problems. But that's not the question. I'm not worried about cross-browser right now. Thank you. – thom Aug 11 '11 at 17:16
  • How could my pencil listen canvas events? That sounds great! Thanks. – thom Aug 11 '11 at 17:17
  • I don't really know how to do it in plain js, but I know how to do it in google closure, so it must be a way to do so without a framework. – Mironor Aug 11 '11 at 17:22
  • @thom It doesn't have to. Your `canvasClicked` handler calls the `pencil.draw` method explicitly - that's how I would implement it. – Šime Vidas Aug 11 '11 at 17:24
  • "My canvas has a tool". Šime Vidas, does it sound weird to you too? It sounds weird to me. Thanks. – thom Aug 11 '11 at 17:28
  • @thom Yes, but that doesn't mean that the `canvasClick` handler cannot call the `draw` method of the independent `pencil` instance. – Šime Vidas Aug 11 '11 at 17:32