Click here to Skip to main content
65,938 articles
CodeProject is changing. Read more.
Articles / web / HTML5

Drawing rubber line using javascript and html5

4.33/5 (6 votes)
2 Jun 2014CPOL2 min read 20.2K   406  
Besides drawing rubber lines you can read about custom cursor and storage of arrays.

Image 1

Introduction

My main goal was to solve the problem of drawing rubber lines on a canvas. I used a transparent copy canvas above (z-index!) the original one. The copy canvas is "visible" only during input process, otherwise <display:"none">.

My program is a little cad-like 2d drawing solution with gravitation (snapping). You can draw lines, multilines, circles and arcs. The intelligent (custom) cursor reflects the relation of the geometric elements and the cursor position.

The data of element are stored in sessionStorage. How to store and retrieve array of objects is not evident: I used JSON functions for them.

The used tooltip solution is not my creation.

You can try this application on this page .

Using the code

I attached a htm file, three js files in the js folder, and custom cursor image files in the cursors folder.

Now I share some important details from the code files:

How to create the copy canvas?

The original canvas in the htm file:

C++
<div id = "canvasId">
    <canvas id="myCanvas" width=...; z-index: 1;">
        Your browser does not support the HTML5 canvas tag.
    </canvas>
</div> 

The copy javascript function:

C++
function SetCanvasLayer (p_canvas, p_divId, p_moveFunc, p_cancelFunc) {
    var rubberDiv = document.getElementById(p_divId);
    var layer = document.getElementById(canvasRubber);
    if (layer == null) {
        canvasRubber = document.createElement('canvas');
        rubberDiv.appendChild(canvasRubber);
        ctxRubber = canvasRubber.getContext("2d");

        canvasRubber.width = p_canvas.width;
        canvasRubber.height = p_canvas.height;
        canvasRubber.setAttribute("style", p_canvas.getAttribute("style"));
        canvasRubber.style.backgroundColor = "transparent";
        canvasRubber.style.zIndex = parseInt(p_canvas.style.zIndex) + 1;
        canvasRubber.style.cursor = "url(Cursors/pencil.png) 6 28, crosshair";
        canvasRubber.style.display = "none";
        canvasRubber.innerHTML = "Your browser does not support the HTML5 canvas tag.";
        canvasRubber.onclick = LayerClick;
        canvasRubber.onmousemove = LayerMouseMove;

        window.addEventListener("keydown", LayerKeyDown, false);
        moveFunction = p_moveFunc;
        cancelFunction = p_cancelFunc;
    }
}

The first click event is handled by the original canvas. Depending on the radio buttons, its function have to call the StartRubberLine function for example. After that the copy canvas becomes "visible", and receives the mouse events.

The LayerMouseMove function is called at mousemove event. This function calls - among others - the DrawRubberLine function:

C++
function DrawRubberLine(pos, clear) {
    if (clear == true) {
        ClearCanvas();
    }

    ctxRubber.strokeStyle = colorRubber;
    ctxRubber.beginPath();
    ctxRubber.moveTo(startx, starty);
    ctxRubber.lineTo(pos.x, pos.y);
    ctxRubber.stroke();
}

Generally we have to clean the canvas before drawing

C++
function ClearCanvas() {
    ctxRubber.clearRect(0, 0, canvasRubber.width, canvasRubber.height);
    var w = canvasRubber.width;
    canvasRubber.width = 1;
    canvasRubber.width = w;
}

The StoreGeomElemObj function stores data into the sessionStorage. The stored data is an array. An item of the array is an object containing numbers, strings and an array of coordinates.

C++
function StoreGeomElemObj(p_elem, p_storageId) {
    var store = sessionStorage.getItem(p_storageId);
    if (store == null) {
        store = new Array(0);
    }
    else {
        store = JSON.parse(store);
    }
    store.push(p_elem);
    sessionStorage.setItem(p_storageId, JSON.stringify(store));
}

To retrieve the original object item use the following funcion:

C++
function GetGeomElemObj(p_index, p_storageId) {
    var store = sessionStorage.getItem(p_storageId)
    if (store == null) {
        return null;
    }
    else {
        store = JSON.parse(store);
        return store[p_index];
    }
}

To obtain the count of elements in an array of objects use the following function:

C++
function GetArrayLength (obj) {
    var i = 0, key;
    for (key in obj) {
        if (obj.hasOwnProperty(key)) {
            i++;
        }
    }
    return i;
};

The gravity system is a complex code containing geometric calculations. For example if the cursor is near to a line endpoint, the cursor changes its shape: pipe or striped pencil during input.

C++
var CursorPencilStriped = "url(cursors/pencilstriped.png) 6 28, crosshair";
 canvasRubber.style.cursor = CursorPencilStriped ;

The gravity system can help you to draw a perpendicular line as well. The arc gravity is your task :) I could do it: see this page.

Finally here is a tip: you can change the direction of the arc returning to the start point of the arc.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)