{ 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); }()); }