Created
July 26, 2021 11:50
-
-
Save PM2Ring/25c503092bca5b4444a1112d2d1ca59b to your computer and use it in GitHub Desktop.
Basic Bezier curve, interactive
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<!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> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment