The acronym SVG stands for Scalable Vector Graphics and refers to graphics that are generated by a geometric specification rather than by pixels, like an image (called rasterized graphics as opposed to the vectorized graphics described here).
The program below fetches the body element first. Then a div element is created and assigned the name qMainDiv. Inside qMainDiv, we add a svg element and put the line element inside it.
The code creates a quadratic bezier curve that interpolates the endpoints and has a center control point that can be dragged. Also, the cursor changes when it is close enough to a one of these points to signal that it may be dragged.
<!DOCTYPE html>
<html>
<head>
<title>XoaX.net's Javascript</title>
</head>
<body>
<script type="text/javascript" src="SvgDraggableQuad.js"></script>
</body>
</html>var qBody = document.getElementsByTagName("body")[0];
// The containing div and all of the variables
var qMainDiv = document.createElement("div");
qMainDiv.style.backgroundColor = "#bbdd99";
qMainDiv.style.width = "600px";
qMainDiv.style.height = "600px";
qMainDiv.style.margin = "20px";
qMainDiv.mbDrag1 = false;
qMainDiv.mbDrag2 = false;
qMainDiv.mbDragC = false;
qMainDiv.mdX1 = 100.0;
qMainDiv.mdY1 = 200.0;
qMainDiv.mdXC = 200.0;
qMainDiv.mdYC = 100.0;
qMainDiv.mdX2 = 300.0;
qMainDiv.mdY2 = 200.0;
qMainDiv.mdDistSq1 = 200.0;
qMainDiv.mdDistSqC = 200.0;
qMainDiv.mdDistSq2 = 200.0;
qMainDiv.mqPoint1 = null;
qMainDiv.mqPointC = null;
qMainDiv.mqPoint2 = null;
qMainDiv.mqQuadSvg = null;
qMainDiv.mqQuadPath = null;
qMainDiv.mqLinePath = null;
qMainDiv.onmousemove = function(e) {
this.SetCursorCoordinates(e);
this.SetCursorDistancesSquared();
// Make a cease for draging each of the three points
if (this.mbDrag1) {
this.mdX1 = this.mdCursorX;
this.mdY1 = this.mdCursorY;
this.mqPoint1.setAttribute('cx', this.mdX1);
this.mqPoint1.setAttribute('cy', this.mdY1);
this.mqLinePath.setAttribute('d', 'M'+this.mdX1+','+this.mdY1+
' L'+this.mdXC+','+this.mdYC+' '+this.mdX2+','+this.mdY2);
this.mqQuadPath.setAttribute('d', 'M'+this.mdX1+','+this.mdY1+
' Q'+this.mdXC+','+this.mdYC+' '+this.mdX2+','+this.mdY2);
} else if (this.mbDrag2){
this.mdX2 = this.mdCursorX;
this.mdY2 = this.mdCursorY;
this.mqPoint2.setAttribute('cx', this.mdX2);
this.mqPoint2.setAttribute('cy', this.mdY2);
this.mqLinePath.setAttribute('d', 'M'+this.mdX1+','+this.mdY1+
' L'+this.mdXC+','+this.mdYC+' '+this.mdX2+','+this.mdY2);
this.mqQuadPath.setAttribute('d', 'M'+this.mdX1+','+this.mdY1+
' Q'+this.mdXC+','+this.mdYC+' '+this.mdX2+','+this.mdY2);
} else if (this.mbDragC){
this.mdXC = this.mdCursorX;
this.mdYC = this.mdCursorY;
this.mqPointC.setAttribute('cx', this.mdXC);
this.mqPointC.setAttribute('cy', this.mdYC);
this.mqLinePath.setAttribute('d', 'M'+this.mdX1+','+this.mdY1+
' L'+this.mdXC+','+this.mdYC+' '+this.mdX2+','+this.mdY2);
this.mqQuadPath.setAttribute('d', 'M'+this.mdX1+','+this.mdY1+
' Q'+this.mdXC+','+this.mdYC+' '+this.mdX2+','+this.mdY2);
} else {
// If the cursor is close to a drag point, change it.
if ((this.mdDistSq1 <= 25) || (this.mdDistSqC <= 25) || (this.mdDistSq2 <= 25)) {
this.style.cursor = "pointer";
} else {
this.style.cursor = "auto";
}
}
};
qMainDiv.onmousedown = function(e) {
this.SetCursorCoordinates(e);
this.SetCursorDistancesSquared();
// Check if either point is in range to be dragged
if (this.mdDistSq1 <= 25) {
this.mbDrag1 = true;
} else if (this.mdDistSqC <= 25) {
this.mbDragC = true;
} else if (this.mdDistSq2 <= 25) {
this.mbDrag2 = true;
}
};
qMainDiv.onmouseup = function(e) {
this.mbDrag1 = false;
this.mbDragC = false;
this.mbDrag2 = false;
};
// The function that is used to calculate the cursor coordinates
qMainDiv.SetCursorCoordinates = function(e) {
var dElementOffsetX = 0;
var dElementOffsetY = 0;
var qElement = this;
do{
dElementOffsetX += qElement.offsetLeft - qElement.scrollLeft;
dElementOffsetY += qElement.offsetTop - qElement.scrollTop;
qElement = qElement.offsetParent
} while(qElement != document.body)
this.mdCursorX = e.pageX - dElementOffsetX;
this.mdCursorY = e.pageY - dElementOffsetY;
}
qMainDiv.SetCursorDistancesSquared = function() {
var dX1 = this.mdX1;
var dY1 = this.mdY1;
var dXC = this.mdXC;
var dYC = this.mdYC;
var dX2 = this.mdX2;
var dY2 = this.mdY2;
// Calculate the distance squared from the cursor to each point
this.mdDistSq1 = (dX1 - this.mdCursorX)*(dX1 - this.mdCursorX)
+ (dY1 - this.mdCursorY)*(dY1 - this.mdCursorY);
this.mdDistSqC = (dXC - this.mdCursorX)*(dXC - this.mdCursorX)
+ (dYC - this.mdCursorY)*(dYC - this.mdCursorY);
this.mdDistSq2 = (dX2 - this.mdCursorX)*(dX2 - this.mdCursorX)
+ (dY2 - this.mdCursorY)*(dY2 - this.mdCursorY);
}
// The whole SVG region
var qQuadSvg = document.createElementNS("http://www.w3.org/2000/svg", "svg");
qQuadSvg.style.width="600px";
qQuadSvg.style.height="600px";
qMainDiv.mqQuadSvg = qQuadSvg;
// The Quadratic interpolation path
var qQuadPath = document.createElementNS("http://www.w3.org/2000/svg", "path");
qQuadPath.setAttribute('d', 'M'+qMainDiv.mdX1+','+qMainDiv.mdY1+
' Q'+qMainDiv.mdXC+','+qMainDiv.mdYC+
' '+qMainDiv.mdX2+','+qMainDiv.mdY2);
qQuadPath.setAttribute('stroke-width', '3');
qQuadPath.setAttribute('stroke', 'rgb(240, 255, 220)');
qQuadPath.setAttribute('fill', 'none');
qMainDiv.mqQuadPath = qQuadPath;
// The two-piece linear path bounding the quadratic
var qLinePath = document.createElementNS("http://www.w3.org/2000/svg", "path");
qLinePath.setAttribute('d', 'M'+qMainDiv.mdX1+','+qMainDiv.mdY1+
' L'+qMainDiv.mdXC+','+qMainDiv.mdYC+' '+qMainDiv.mdX2+','+qMainDiv.mdY2);
qLinePath.setAttribute('stroke-width', '1');
qLinePath.setAttribute('stroke', 'rgb(240, 255, 220)');
qLinePath.setAttribute('fill', 'none');
qMainDiv.mqLinePath = qLinePath;
// The first endpoint
var qPoint1 = document.createElementNS("http://www.w3.org/2000/svg", "circle");
qPoint1.setAttribute('cx', qMainDiv.mdX1);
qPoint1.setAttribute('cy', qMainDiv.mdY1);
qPoint1.setAttribute('r', 4);
qPoint1.setAttribute('fill', 'rgb(240, 255, 220)');
qMainDiv.mqPoint1 = qPoint1;
// The middle control point
var qPointC = document.createElementNS("http://www.w3.org/2000/svg", "circle");
qPointC.setAttribute('cx', qMainDiv.mdXC);
qPointC.setAttribute('cy', qMainDiv.mdYC);
qPointC.setAttribute('r', 4);
qPointC.setAttribute('fill', 'rgb(240, 255, 220)');
qMainDiv.mqPointC = qPointC;
// The second endpoint
var qPoint2 = document.createElementNS("http://www.w3.org/2000/svg", "circle");
qPoint2.setAttribute('cx', qMainDiv.mdX2);
qPoint2.setAttribute('cy', qMainDiv.mdY2);
qPoint2.setAttribute('r', 4);
qPoint2.setAttribute('fill', 'rgb(240, 255, 220)');
qMainDiv.mqPoint2 = qPoint2;
// Put all of the elements together
qQuadSvg.appendChild(qQuadPath);
qQuadSvg.appendChild(qLinePath);
qQuadSvg.appendChild(qPoint1);
qQuadSvg.appendChild(qPointC);
qQuadSvg.appendChild(qPoint2);
qMainDiv.appendChild(qQuadSvg);
qBody.appendChild(qMainDiv);© 20072025 XoaX.net LLC. All rights reserved.