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