On right click draw triangle to the canvas

Posted on

Problem

This is a simple program that using easelJS adds functionality to the right click, when the right mouse button is clicked a triangle is drawn to the screen. I am just wanting to get the opinions of others on my coding style and how it could be improved.

body{
    margin: 0;
    background-color: #d3d3d3;
    font-family: Sans-Serif;
}

h1{
    font-weight: 100;
    text-align: center;
}

canvas{
    display: block;
    margin: auto;
    background-color: #ffffff;
    border: solid 1px #000000;
}
<!DOCTYPE html>

<html>

    <head>
        <title>Draw Triangle</title>
        <link rel="stylesheet" href="styles.css"/>
        <script src="https://code.createjs.com/easeljs-0.8.2.min.js"></script>
        <script>
            var stage;
            var triangle;

            function init() {
                stage = new createjs.Stage("myCanvas");

                stage.addEventListener("stagemousedown", function(evt) {
                    var e = evt.nativeEvent;
                    var key = e.which || e.keyCode;
                    if(key !== 1){
                        addTriangle(evt.stageX, evt.stageY);
                    }
                });
            }

            function addTriangle(x, y){
                triangle = new createjs.Shape();
                triangle.graphics.beginFill("#000000");
                triangle.graphics.moveTo(x, y).lineTo(x-100, y).lineTo(x-50,y-100).lineTo(x, y);
                stage.addChild(triangle);
                stage.update();
            }
        </script>
    </head>

    <body onload="init();">
        <h1>Right click to draw a Triangle to the canvas</h1>
        <canvas id="myCanvas" width="900" height="700"></canvas>
    </body>

</html>

Solution

General problems

  • It is better to add events via addEventListener rather than in the HTML, this keeps the source code together making it easier to maintain. It also protects your code from 3rd party code overwriting the event handler. If some code later sets window.onload = theirFunction; it overwrites your event that will not get called.

  • Keep your variables out of the global scope if possible. stage and triangle do not need to be in global scope. triangle is only used in the one function so define it there.

  • Use const rather than var if you do not intend to modify a variable.

  • Don’t let lines get too long. 80 character is the usual limit. If a line gets longer than that break it into multiple lines.

  • Right click will bring up the context menu. You can prevent this by listening to the contextmenu event and calling preventDefault on the event object.

  • Why the defaulting to keyCode? is that even defined for the easelJS event ?

  • Don’t add needless code. You define a variable for evt.nativeEvent, and e.which. These are not really needed.

  • Use correct names for variables. You use key for which button is pressed, this can be confusing when code gets longer.

  • You say you want to add a triangle on the right click but the code you had will add a triangle for any button except the left button.

  • Make your code easier to read by using spaces after commas, between operators, after statements and befor { eg if(bar===poo){foo(a,b+2,c);} is better if (bar === poo) { foo(a, b + 2, c); }

The rewrite

Rewrite of your code using the above.

body{
    margin: 0;
    background-color: #d3d3d3;
    font-family: Sans-Serif;
}

h1{
    font-weight: 100;
    text-align: center;
}

canvas{
    display: block;
    margin: auto;
    background-color: #ffffff;
    border: solid 1px #000000;
}
<!DOCTYPE html>

<html>

    <head>
        <title>Draw Triangle</title>
        <link rel="stylesheet" href="styles.css"/>
        <script src="https://code.createjs.com/easeljs-0.8.2.min.js"></script>
        <script>
            addEventListener("load", init);  // add the load event listener 
            function init() {
                // I am getting canvas as I need it to get the contextmenu event
                const canvas = document.getElementById("myCanvas");

                // use const for variables that will not change.
                const stage = new createjs.Stage(canvas);
                stage.addEventListener("stagemousedown", mouseDown);

                // to prevent the context menu popping up
                canvas.addEventListener("contextmenu", (event) => {
                    event.preventDefault();
                });

                // simplify the mouseDown event
                function mouseDown(evt) {
                    if (evt.nativeEvent.which === 3) {
                        addTriangle(evt.stageX, evt.stageY);
                    }
                }

                function addTriangle(x, y) {
                    const triangle = new createjs.Shape(); // define triangle in the scope it is used
                    triangle.graphics.beginFill("#000");
                    triangle.graphics       // break the line to make it more readable and easier to modify
                        .moveTo(x, y)       // use spaces after commas
                        .lineTo(x - 100, y) // and spaces around operators
                        .lineTo(x - 50, y - 100)
                        .lineTo(x, y);
                    stage.addChild(triangle);
                    stage.update();
                }
            }
        </script>
    </head>
    <body>
        <h1>Right click to draw a Triangle to the canvas</h1>
        <canvas id = "myCanvas" width = "900" height = "700"></canvas>
    </body>
</html>

Additional notes.

I don’t know what your intention is but the triangle seems a little odd not being centered on the mouse click. Also I would define the triangle as a abstract path rather than hard coded to the function.

Is there a reason you put the code in the head of the document. You could have placed it at the bottom of the page and avoided having to wait for the page load event.

Also, maybe you are wanting to learn easelJS, but the load time of easelJS is substantial and what you do can just as easily be done using the native 2D API.

I strongly believe that you should have a very good reason to use a 3rd party library, especially when you are learning. You are best spending your time learning the native (and very good and performant) APIs. You may not always be able to use the library, but you will always have access to the native API

Rewrite without easelJS

To match your code I have implemented a very simple stage. Though what you do does not require a stage object and could be a lot simplier.

The simplest way to achieve the same functionality.

Leave a Reply

Your email address will not be published. Required fields are marked *