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:
<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:
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:
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
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.
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:
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:
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.
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.