Skip to content

Instantly share code, notes, and snippets.

@LeetCodes
Created November 17, 2021 14:39
Show Gist options
  • Save LeetCodes/96282ba3df87550d427f064e8036dd94 to your computer and use it in GitHub Desktop.
Save LeetCodes/96282ba3df87550d427f064e8036dd94 to your computer and use it in GitHub Desktop.
ClipPathTool
main
#elEdit
img#elImg(src="https://images.unsplash.com/photo-1534248176570-86222955fe6a?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=1855be4bc357982affb3d2abc8942885&auto=format&fit=crop&w=700&q=60")
#elPreview
img#elClipImg(src="https://images.unsplash.com/photo-1534248176570-86222955fe6a?ixlib=rb-0.3.5&ixid=eyJhcHBfaWQiOjEyMDd9&s=1855be4bc357982affb3d2abc8942885&auto=format&fit=crop&w=700&q=60")
input#elDump(readonly)
input#elDump2(readonly)
#elControls
input#elImgUrl(placeholder="paste your image url here")
button#elClearBtn(disabled) clear all vertices
{
const el = elEdit;
// el bbox
const bbox = el.getBoundingClientRect();
// canvas
const canvas = document.createElement("canvas");
canvas.width = bbox.width;
canvas.height = bbox.height;
el.appendChild(canvas);
// 2d render context
const ctx = canvas.getContext("2d");
// points
const points = [];
// evs
el.addEventListener("mousedown", e => {
// left btn
if (e.buttons === 1) {
// norm x y
const bbox = el.getBoundingClientRect();
const x = (e.clientX - bbox.left)/bbox.width;
const y = (e.clientY - bbox.top)/bbox.height;
points.push([x, y]);
elClearBtn.disabled = false;
}
// right btn
else if (e.buttons === 2) {
// rm last poin
if (points.length !== 0)
points.length -= 1;
if (points.length === 0)
elClearBtn.disabled = true;
return;
}
});
// right click for rm points, stp showing ctxmenu
el.addEventListener("contextmenu", e => {
e.preventDefault();
});
// clear all points
elClearBtn.addEventListener("click", e => {
points.length = 0;
e.target.disabled = true;
});
// img url
elImgUrl.addEventListener("input", e => {
elImg.src = e.target.value;
elClipImg.src = e.target.value;
})
// render strokes
ctx.fillStyle = "red";
ctx.strokeStyle = "black";
ctx.lineWidth = 0.6;
(function tick(){
//
// canvas
//
ctx.clearRect(0,0,ctx.canvas.width,ctx.canvas.height);
ctx.beginPath();
for (const [i, [x,y]] of points.entries()) {
const _x = x * bbox.width;
const _y = y * bbox.height;
if (i === 0) {
ctx.moveTo(_x, _y);
ctx.fillRect(_x-1.5, _y-1.5, 3, 3);
}
else {
ctx.lineTo(_x, _y);
}
}
ctx.stroke();
// line to point0
if (points.length > 1) {
const [xN, yN] = points[points.length-1];
const [x0, y0] = points[0];
ctx.beginPath();
ctx.setLineDash([3,5]);
ctx.moveTo(xN*bbox.width, yN*bbox.height);
ctx.lineTo(x0*bbox.width, y0*bbox.height);
ctx.stroke();
ctx.setLineDash([]);
}
//
// dump data
//
// vertice pairs
const vs = [];
const vs2 = [];//map to 1 of four corners
for (const [x, y] of points) {
vs.push(`${(x*100).toFixed(1)}% ${(y*100).toFixed(1)}%`);
vs2.push(`${Math.round(x)*100}${Math.round(x)?"%":""} ${Math.round(y)*100}${Math.round(y)?"%":""}`);
}
// polygon
const cssPolygonStr = `polygon(${vs.join(",")})`;
elDump.value = `${cssPolygonStr};`;
const cssPolygonStr2 = `polygon(${vs2.join(",")})`;
elDump2.value = `${cssPolygonStr2};`;
//
// apply clippath to preview img(#elClipImg)
//
if (vs.length)
elPreview.style.clipPath = cssPolygonStr;
else
elPreview.style.clipPath = "none";
setTimeout(tick, 1000/10);
}());
}
body {
display:flex;
justify-content:center;
align-items:center;
min-height:100vh;
}
main {
flex:0 0 auto;
width:600px;
display:flex;
flex-flow:row wrap;
justify-content:center;
align-items:center;
align-content:center;
box-shadow:0 0 3px rgba(0,0,0,0.3);
position:relative;
}
#elEdit, #elPreview {
flex:0 0 auto;
width:300px;
height:300px;
position:relative;
}
#elEdit:before {
position:absolute;
pointer-events:none;
content:"edit";
font:1em monospace;
background:deeppink;
padding:1ch;
}
main:before {
position:absolute;
top:0; left:50%;
pointer-events:none;
content:"preview";
font:1em monospace;
background:deeppink;
padding:1ch;
}
#elEdit img, #elPreview img {
width:100%; height:100%;
object-fit:fill;
position:absolute;
display:block;
opacity:0.5;
}
#elEdit canvas {
position:absolute;
}
#elDump, #elDump2 {
width:100%;
height:20px;
border:thin solid rgba(0,0,0,0.1);
box-sizing:border-box;
font:0.8em monospace;
padding:0.2em 3ch;
}
#elControls {
display:flex;
border:thin solid rgba(0,0,0,0.1);
width:100%;
}
#elImgUrl {
border:0 none;
border-right:thin solid rgba(0,0,0,0.1);
box-sizing:border-box;
margin:0;
display:block;
flex:1 1 auto;
padding:0 1ch;
}
#elClearBtn {
border:0 none;
display:block;
padding:1ch;
margin:0;
box-sizing:border-box;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment