Reputation: 8379
I am looking for a way to draw a line on mouse start to end. For example I have DIV and I have moved the mouse in circular way. But I want a line to be drawn in the path mouse is moved.
I am not looking for any HTML5 solution. I want it to be worked even in all modern browsers.
Please help me on this.
Upvotes: 1
Views: 3629
Reputation: 66389
I have written something 8 years ago, revised it 6 years ago and checked it now - still working. It's drawing lines by clicking on two points in the screen, but can be changed to mouse move instead with little tweaking.
It's in pure JavaScript, essentially it's appending pixel sized images to the document.
I will write here the code as-is. Please note it's really old and while working, might not be best practice.
var PIXEL_PATH="https://i.sstatic.net/QXTrN.gif";
var ST_LINE=1;
var ST_CIRCLE=2;
var strImageData="";
var strUserInput="";
var strImageName="";
var iPointsCount=0;
var iNumCalls=0;
var loadComplete=false;
var arrLines=new Array();
var arrRedo=new Array();
var strPoints="";
var arrImages;
var objWin;
var INFINITY=-999999;
var iLastX=INFINITY, iLastY=INFINITY;
var drawStyle=ST_LINE;
var arrPoints=new Array();
var iCurrentImage=0;
var blnLineFinished=true;
var blnLoading=true;
var strCurrentPoints="";
document.onclick = DocumentClick;
document.onkeyup = DocumentKeyup;
self.onload=Init;
function Init()
{
DrawPoint(0, 0);
CommitDraw();
}
function DrawImage()
{
var x1, x2, y1, y2;
var iStep=12;
blnLoading = true;
for (j=0; j<document.images.length; j++)
document.images[j].style.visibility = "hidden";
if (objWin)
objWin.close();
arrLines = new Array();
arrRedo = new Array();
document.forms[0].redo.disabled = true;
iLastX=INFINITY;
iLastY=INFINITY;
DrawPoint(0, 0);
CommitDraw();
if ((strImageData.length % 12) != 0)
iStep = 13;
for (i=0; i<strImageData.length; i+=iStep)
{
drawStyle = (iStep == 12)?ST_LINE:ToNumber(strImageData.substr(i, 1));
x1 = ToNumber(strImageData.substr(i+iStep-12, 3));
y1 = ToNumber(strImageData.substr(i+iStep-12+3, 3));
x2 = ToNumber(strImageData.substr(i+iStep-12+6, 3));
y2 = ToNumber(strImageData.substr(i+iStep-12+9, 3));
Line(x1, y1, x2, y2);
}
return true;
}
function Random()
{
event.cancelBubble = true;
var x1, x2, x1_old;
var y1, y2, y1_old;
var z=0;
if (drawStyle == ST_CIRCLE)
{
x1=Rnd(document.body.clientWidth-100)+100;
y1=Rnd(document.body.clientHeight-100)+100;
x2 = x1+MIN(ABS(x1-100), ABS(document.body.clientWidth-100-x1));
y2 = y1+MIN(ABS(y1-100), ABS(document.body.clientHeight-100-y1));
x1_old = x1;
y1_old = y1;
while ((R(x1, y1, x2, y2) >= ABS(x2-x1_old)) || (R(x1, y1, x2, y2) >= ABS(y2-y1_old)))
{
x1 += (ABS(x1-100) > ABS(document.body.clientWidth-100-x1))?-1:1;
y1 += (ABS(y1-100) > ABS(document.body.clientHeight-100-y1))?-1:1;
z++;
if (z >= 100)
break;
}
}
else
{
x1=Rnd(document.body.clientWidth-30)+30;
y1=Rnd(document.body.clientHeight-30)+30;
x2=Rnd(document.body.clientWidth-30)+30;
y2=Rnd(document.body.clientHeight-30)+30;
}
ClearLastPoint();
Line(x1, y1, x2, y2);
arrRedo = new Array();
document.forms[0].redo.disabled = true;
return true;
}
function ToNumber(str) {return (str*(-1)*(-1));}
function Rnd(num) {return parseInt(Math.random()*num);}
function DocumentClick()
{
var iCurX=window.event.x, iCurY=window.event.y;
// blnLoading=false;
if ((iLastX != INFINITY )&&(iLastY != INFINITY))
{
Line(iLastX, iLastY, iCurX, iCurY);
if (drawStyle != ST_CIRCLE)
{iLastX = iCurX; iLastY = iCurY;}
}
else
{
iLastX = iCurX;
iLastY = iCurY;
}
arrRedo = new Array();
document.forms[0].redo.disabled = true;
return true;
}
function DocumentKeyup()
{
if (document.forms[0].all("load"))
return false;
strUserInput += String.fromCharCode(self.event.keyCode);
if (strUserInput.toLowerCase().indexOf("shadow")>=0)
{
var objInput=document.createElement("INPUT");
objInput.name = objInput.id = "load";
objInput.type = "button";
objInput.value = "Load";
objInput.onclick = Load;
document.forms[0].appendChild(objInput);
return true;
}
if (strUserInput.length > 999)
strUserInput.length = "";
return false
}
function Line(x1, y1, x2, y2)
{
arrLines[arrLines.length] = drawStyle+AddZeros(x1, 3)+AddZeros(y1, 3)+
AddZeros(x2, 3)+AddZeros(y2, 3);
blnLineFinished = false;
strCurrentPoints = "";
document.forms[0].undo.disabled = false;
arrPoints = new Array();
iCurrentImage = 0;
if (!blnLoading)
{
divMsg.style.visibility = "visible";
divMsg.style.left = x1+"px";
divMsg.style.top = y1+"px";
}
arrImages=new Array();
if (drawStyle == ST_CIRCLE)
return Circle(x1, y1, x2, y2);
if (x1 == x2)
{
for (y=MIN(y1, y2); y<=MAX(y1, y2); y++)
DrawPoint(x1, y);
return EndLine();
}
if (ABS((x2-x1))>=ABS((y2-y1)))
{
for (x=MIN(x1, x2); x<=MAX(x1, x2); x++)
DrawPoint(x, Y(x, x1, y1, x2, y2));
return EndLine();
}
else
{
for (y=MIN(y1, y2); y<=MAX(y1, y2); y++)
DrawPoint(X(y, x1, y1, x2, y2), y);
return EndLine();
}
}
function Circle(x1, y1, x2, y2)
{
var y, x, r=R(x1, y1, x2, y2);
var iFirst=(x1-r);
var iLast=(x1+r);
var iFirst2=(y1-r);
var iLast2=(y1+r);
for (x=iFirst; x<=iLast; x++)
{
y = Y2(r, x, x1, y1);
DrawPoint(X2(r, y, x1, y1), y);
DrawPoint(X3(r, y, x1, y1), y);
y = Y3(r, x, x1, y1);
DrawPoint(X2(r, y, x1, y1), y);
DrawPoint(X3(r, y, x1, y1), y);
}
for (y=iFirst2; y<=iLast2; y++)
{
x = X2(r, y, x1, y1);
DrawPoint(x, Y2(r, x, x1, y1));
DrawPoint(x, Y3(r, x, x1, y1));
x = X3(r, y, x1, y1);
DrawPoint(x, Y2(r, x, x1, y1));
DrawPoint(x, Y3(r, x, x1, y1));
}
iLastX=INFINITY;
iLastY=INFINITY;
return EndLine();
}
function R(x1, y1, x2, y2)
{
return Math.sqrt(((x2-x1)*(x2-x1))+((y2-y1)*(y2-y1)));
}
function EndLine()
{
CommitDraw();
strPoints = strPoints.substr(0, strPoints.length-1)+"|";
HideMessage();
if (!blnLoading)
divPointsCount.innerHTML = "0";
}
function HideMessage()
{
if (blnLineFinished)
{
divMsg.style.visibility = "hidden"; return true;
}
setTimeout("HideMessage();", 100);
}
function Y(x, x1, y1, x2, y2)
{
return (((y2-y1)/(x2-x1))*(x-x1))+y1;
}
function X(y, x1, y1, x2, y2)
{
return (((x2-x1)/(y2-y1))*(y-y1))+x1;
}
function Y2(r, x, x0, y0)
{
return (y0+Math.sqrt(ABS((r*r)-((x-x0)*(x-x0)))));
}
function X2(r, y, x0, y0)
{
return (x0+Math.sqrt(ABS((r*r)-((y-y0)*(y-y0)))));
}
function Y3(r, x, x0, y0)
{
return (y0-Math.sqrt(ABS((r*r)-((x-x0)*(x-x0)))));
}
function X3(r, y, x0, y0)
{
return (x0-Math.sqrt(ABS((r*r)-((y-y0)*(y-y0)))));
}
function ABS(n) {return (n>=0)?n:(n*-1);}
function MAX(a1, a2) {return (a1>=a2)?a1:a2;}
function MIN(a1, a2) {return (a1<=a2)?a1:a2;}
function AddZeros(iNumber, iZeros)
{
var strZeros="";
for (j=0; j<iZeros; j++)
strZeros += "0";
return (strZeros.substr(0, iZeros-(iNumber+"").length)+iNumber+"");
}
function DrawPoint(x, y)
{
if (PointExists(parseInt(x), parseInt(y)))
return false;
iPointsCount++;
var objImage=document.createElement("IMG");
objImage.id = "i"+iPointsCount;
objImage.name = "i"+iPointsCount;
objImage.src = PIXEL_PATH;
objImage.width = objImage.height = 1;
objImage.border = 0;
objImage.style.position = "absolute";
objImage.style.top = parseInt(y)+"px";
objImage.style.left = parseInt(x)+"px";
strCurrentPoints += parseInt(x)+","+parseInt(y)+"|";
arrPoints[arrPoints.length] = objImage;
// document.body.appendChild(objImage);
strPoints += "i"+iPointsCount+",";
return true;
}
function CommitDraw()
{
if (iCurrentImage >= arrPoints.length)
{
blnLineFinished = true; return true;
}
if (blnLoading)
{
for (iCurrentImage=0; iCurrentImage<arrPoints.length; iCurrentImage++)
document.body.appendChild(arrPoints[iCurrentImage]);
blnLineFinished = true;
}
else
{
document.body.appendChild(arrPoints[iCurrentImage]);
iCurrentImage++;
divPointsCount.innerHTML = (parseInt(divPointsCount.innerHTML)+1)+"";
setTimeout("CommitDraw();", 1);
}
}
function PointExists(x, y)
{
return (strCurrentPoints.indexOf(parseInt(x)+","+parseInt(y)+"|")>=0);
}
function GetImageData()
{
var strAns="";
for (k=0; k<arrLines.length; k++)
strAns += arrLines[k];
return strAns;
}
function Undo()
{
event.cancelBubble=true;
if (arrLines.length>0)
ClearLastLine();
arrRedo[arrRedo.length] = arrLines[arrLines.length-1];
document.forms[0].redo.disabled = false;
var arrTemp=new Array();
for (i=0; i<arrLines.length-1; i++)
arrTemp[i] = arrLines[i];
arrLines = arrTemp;
document.forms[0].undo.disabled = (arrLines.length == 0);
if ((drawStyle == ST_CIRCLE)||(arrLines.length == 0))
{
iLastX=INFINITY;
iLastY=INFINITY;
}
else
{
iLastX=parseInt(document.getElementById("i"+iPointsCount).style.left);
iLastY=parseInt(document.getElementById("i"+iPointsCount).style.top);
}
}
function Redo()
{
event.cancelBubble=true;
if (arrRedo.length == 0)
return false;
var strLine=arrRedo[arrRedo.length-1];
drawStyle = ToNumber(strLine.substr(0, 1));
var x1=ToNumber(strLine.substr(1, 3));
var y1=ToNumber(strLine.substr(4, 3));
var x2=ToNumber(strLine.substr(7, 3));
var y2=ToNumber(strLine.substr(10, 3));
Line(x1, y1, x2, y2);
var arrTemp=new Array();
for (i=0; i<arrRedo.length-1; i++)
arrTemp[i] = arrRedo[i];
arrRedo = arrTemp;
document.forms[0].redo.disabled = (arrRedo.length == 0);
if (drawStyle == ST_CIRCLE)
{
iLastX=INFINITY;
iLastY=INFINITY;
}
else
{
iLastX = x2;
iLastY = y2;
}
}
function ClearLastLine()
{
var strToClear="";
//alert("points: "+strPoints);
for (j=strPoints.length-2; (j>=0)&&(strPoints.charAt(j) != "|"); j--)
strToClear += strPoints.charAt(j);
strPoints = strPoints.substr(0, strPoints.length-strToClear.length-1);
var strTmp="";
for (k=strToClear.length-1; k>=0; k--)
strTmp += strToClear.charAt(k);
strToClear = strTmp;
var arrTmp=strToClear.split(",");
iPointsCount -= arrTmp.length;
for (i=0; i<arrTmp.length; i++)
document.body.removeChild(document.getElementById(arrTmp[i]));
}
function ClearLastPoint()
{
iLastX=INFINITY;
iLastY=INFINITY;
event.cancelBubble=true;
}
function ToggleShape(a)
{
event.cancelBubble=true;
if (drawStyle == ST_CIRCLE)
{
a.value = "Circle";
drawStyle = ST_LINE;
return ClearLastPoint();
}
if (drawStyle == ST_LINE)
{
a.value = "Line";
drawStyle = ST_CIRCLE;
return ClearLastPoint();
}
return false;
}
It comes along with such HTML:
<form>
<input name="clear" id="clear" type=button value="*" onclick="ClearLastPoint();" />
<input name="undo" id="undo" type=button value="Undo" onclick="Undo();" DISABLED />
<input name="redo" id="redo" type=button value="Redo" onclick="Redo();" DISABLED />
<input name="random" id="random" type=button value="Random" onclick="Random();" />
<input name="circle" id="circle" type=button value="Circle" onclick="ToggleShape(this);" />
</form>
You can see it online in this fiddle. It's using a single pixel image, you can download it here. (right click and choose Save As)
Originally it also supported saving the drawing to server and loading saved drawings using classic ASP but I assume it's not relevant for you so I've omitted it from the code.
Upvotes: 1
Reputation: 6422
If you want it to work in all modern browsers then use HTML5
if you want to support old browsers then you could use the http://raphaeljs.com/ JS library
Raphael uses SVG if available, VML if not. Which Basically every browser except IE8 and below will use SVG.
Upvotes: 3