Skip to content

Instantly share code, notes, and snippets.

@PM2Ring
Created July 26, 2021 11:50
Show Gist options
  • Select an option

  • Save PM2Ring/25c503092bca5b4444a1112d2d1ca59b to your computer and use it in GitHub Desktop.

Select an option

Save PM2Ring/25c503092bca5b4444a1112d2d1ca59b to your computer and use it in GitHub Desktop.
Basic Bezier curve, interactive
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>SVG Bézier</title>
<style id="mystyle">
circle {
stroke: #222;
stroke-width: 0.5;
stroke-opacity: 0.25;
fill-opacity: 0.75;
}
.hull {
stroke: #555;
stroke-width: 0.5;
stroke-dasharray: 2 2;
fill: none;
}
.bezier {
stroke: #000;
stroke-width: 1;
fill: none;
}
</style>
</head>
<body>
<svg version="1.0" xmlns="http://www.w3.org/2000/svg"
viewbox="0 0 200 200"/>
</body>
<script>
var svg = document.querySelector("svg"),
things = [],
dragData = {
target: null, ox: 0, oy: 0, x: 0, y: 0
};
function makeDot(x, y, r, color) {
const a = document.createElementNS(svg.namespaceURI, 'circle');
a.setAttribute("cx", x);
a.setAttribute("cy", y);
a.setAttribute("r", r);
a.setAttribute("fill", color);
svg.appendChild(a);
a.addEventListener("mousedown", onStart, false);
a.addEventListener("touchstart", onStart, false);
things.push(a);
}
function makePath(cls, codes) {
const a = document.createElementNS(svg.namespaceURI, 'path');
a.setAttribute("class", cls);
a.dataset.codes = codes;
updatePath(a);
svg.appendChild(a);
things.push(a);
}
function updatePath(p) {
const codes = p.dataset.codes;
let data = "";
for (let i=0; i<4; i++)
data += codes.charAt(i) + dotXY(things[i]) + " ";
p.setAttribute("d", data);
}
function dotXY(a) {
return a.cx.baseVal.value.toFixed(3) +
',' + a.cy.baseVal.value.toFixed(3);
}
function svgPointer(evt) {
const coords = evt.touches ? evt.touches[0] : evt;
const pt = new DOMPoint(coords.clientX, coords.clientY);
return pt.matrixTransform(evt.target.getScreenCTM().inverse());
}
function onStart(evt) {
if (dragData.target)
return;
const tgt = evt.target;
const isTouch = evt.type == "touchstart";
tgt.addEventListener(isTouch ? "touchmove" : "mousemove",
onMove, false);
tgt.addEventListener(isTouch ? "touchend" : "mouseup",
onEnd, false);
const pt = svgPointer(evt);
dragData.target = tgt;
dragData.ox = pt.x - tgt.cx.baseVal.value;
dragData.oy = pt.y - tgt.cy.baseVal.value;
}
function clamp(n, lo, hi) {
return Math.max(lo, Math.min(n, hi));
}
function onMove(evt) {
evt.preventDefault()
const pt = svgPointer(evt);
dragData.x = clamp(pt.x - dragData.ox, 0, 200);
dragData.y = clamp(pt.y - dragData.oy, 0, 200);
render();
}
function onEnd(evt) {
evt.target.removeEventListener(
evt.type == "touchend" ? "touchmove" : "mousemove",
onMove);
dragData.target = null;
}
function render() {
const tgt = dragData.target;
tgt.cx.baseVal.value = dragData.x;
tgt.cy.baseVal.value = dragData.y;
updatePath(things[4]);
updatePath(things[5]);
}
(function () {
const r = 12;
makeDot(20, 20, r, "#e55");
makeDot(180, 20, r, "#ea5");
makeDot(180, 180, r, "#5f5");
makeDot(20, 180, r, "#78f");
makePath("hull", "MLLL");
makePath("bezier", "MC");
})();
</script>
</html>
@PM2Ring

PM2Ring commented Aug 15, 2026

Copy link
Copy Markdown
Author

Live demo on SageMathCell.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment