裁剪正多边形
<style>#mydiv {
width: 200px;
height: 200px;
background: gray;
}
.papa > div, .papa > p { margin: 20px 0; }
.papa label, .papa input { margin: 0 8px; }
</style>
<div class="papa">
<p>
<input id="btnReset" type="button" value="重置" />
<label for="numLen">宽高:</label>
<input id="numLen" type="number" value="200" min="100" max="1000" />
<label for="numPoint">边数:</label>
<input id="numPoint" type="number" value="3" min="3" max="360" />
<input id="btnOk" type="button" value="裁剪" />
</p>
<div id="mydiv"></div>
<div id="msgBox"></div>
</div>
<script>
let clipBox = (xx,points) => {
if(points < 3) points = 3;
let x0 = y0 = r = xx / 2, pointsAr = [];
for(let i = 0; i < points; i ++) {
let hudu = Math.PI / 180 * 360 / points * i;
let x1 = x0 + Math.cos(hudu) * r, y1 = y0 + Math.sin(hudu) * r;
pointsAr.push(x1 + 'px ' + y1 + 'px');
}
return `polygon(${pointsAr.join(',')})`;
}
let limit = (box,min,max) => {
if(box.value < min) box.value = min;
if(box.value > max) box.value = max;
}
numPoint.onchange = () => limit(numPoint,3,360);
numLen.onchange = () => limit(numLen,60,600);
btnOk.onclick = () => {
mydiv.style.width = numLen.value + 'px';
mydiv.style.height = numLen.value + 'px';
mydiv.style.clipPath = clipBox(numLen.value, numPoint.value);
msgBox.innerText = 'clip-path: ' + mydiv.style.clipPath + ';';
}
btnReset.onclick = () => {
mydiv.style.clipPath = '';
mydiv.style.width = '200px';
mydiv.style.height = '200px';
numLen.value = '200';
numPoint.value = '3';
msgBox.innerText = '';
}
</script>
这是使用 clip-path: poligon() 沿元素边缘裁剪出最大化多边形的小程序,实现方式类似于割圆法,边数越多,裁剪的形状越近似圆形。代码:
<style>
#mydiv {
width: 200px;
height: 200px;
background: gray;
}
.papa > div, .papa > p { margin: 20px 0; }
.papa label, .papa input { margin: 0 8px; }
</style>
<div class="papa">
<p>
<input id="btnReset" type="button" value="重置" />
<label for="numLen">宽高:</label>
<input id="numLen" type="number" value="200" min="100" max="1000" />
<label for="numPoint">边数:</label>
<input id="numPoint" type="number" value="3" min="3" max="360" />
<input id="btnOk" type="button" value="裁剪" />
</p>
<div id="mydiv"></div>
<div id="msgBox"></div>
</div>
<script>
let clipBox = (xx,points) => {
if(points < 3) points = 3;
let x0 = y0 = r = xx / 2, pointsAr = [];
for(let i = 0; i < points; i ++) {
let hudu = Math.PI / 180 * 360 / points * i;
let x1 = x0 + Math.cos(hudu) * r, y1 = y0 + Math.sin(hudu) * r;
pointsAr.push(x1 + 'px ' + y1 + 'px');
}
return `polygon(${pointsAr.join(',')})`;
}
let limit = (box,min,max) => {
if(box.value < min) box.value = min;
if(box.value > max) box.value = max;
}
numPoint.onchange = () => limit(numPoint,3,360);
numLen.onchange = () => limit(numLen,60,600);
btnOk.onclick = () => {
mydiv.style.width = numLen.value + 'px';
mydiv.style.height = numLen.value + 'px';
mydiv.style.clipPath = clipBox(numLen.value, numPoint.value);
msgBox.innerText = 'clip-path: ' + mydiv.style.clipPath + ';';
}
btnReset.onclick = () => {
mydiv.style.clipPath = '';
mydiv.style.width = '200px';
mydiv.style.height = '200px';
numLen.value = '200';
numPoint.value = '3';
msgBox.innerText = '';
}
</script>参与计算的圆心坐标 x0,y0,还有半径 r,在实现正多边形裁剪中,它们的值都一样,只是为了严谨性和可以体现计算依据,保留了各自的变量 名。核心问题在后续回复中会有进一步解释。
本帖最后由 马黑黑 于 2023-6-16 14:36 编辑
本帖的核心,要解决的问题同等于:
已知圆心坐标{x0,y0}、半径r和夹角deg,求圆周上对应点的xy坐标。
圆周上任意一点连接到圆心,与通过圆心的水平线形成夹角(下称夹角,算式里用 deg 表示),这个夹角换算成弧度 hudu 后,便可通过正弦、余弦函数计算出圆周上此点的坐标{x1,y1}:
x1=x0+sin(hudu)*r
y1=y0+cos(hudu)*r
而角度转弧度的公式为: 2π/360*角度 ,简化为π/180*角度 ,则弧度:
hudu = π/180*deg
理解以上数学原理后,我们就可以在一个宽高尺寸为 ww 的矩形元素上切割出最大化的N边形(N≥3):
let x0 = y0 =r = ww / 2, pathAr = [];
for(let i = 0; i < N; i++) {
let hudu = Math.PI / 180 * 360 / N * i;
let x1 = x0 + sin(hudu) * r, y1 = y0 + cos(hudu) * r;
pathAr.pushe(x1 + 'px ' + y1 + 'px');
}
let polyStr = pathAr.join(',');
上面的示范代码中:
我们首先设定了圆心坐标变量 x0 和 y0,圆的半径 r,它们都等于矩形元素宽高尺寸 ww 的一半,我们还设定了一个路径数组变量 pathAr 用以存储圆周上各个N边形的角即在圆周上的点的xy坐标值。
接着我们用一个 for 循环方法,遍历N边形的每一个角(点),并且:
① 计算出圆周上 i 点的夹角 360 / N * i 并换算成弧度 Math.PI / 180 * 360 / N * i;
② 用正、余弦函数分别计算出 i 点xy坐标值 x1 y1;
③ 将 x1 y1 以 x1px y1px 的形式存储到数组 pathAr中;
最后,将 pathAr 数组用 join 方法整合起来,形成 clip-path 裁剪路径字符串,可以 console.log(polyStr) 查看结果。
想到已是不易,做到更是不简单。。。 动了前面的数字,变三角形了{:4_189:} 好神的,我改好数字就出来代码了 小辣椒 发表于 2023-6-16 13:56
好神的,我改好数字就出来代码了
就出裁剪路径的代码 樵歌 发表于 2023-6-16 13:53
动了前面的数字,变三角形了
默认是三个边,可以改 南无月 发表于 2023-6-16 12:44
想到已是不易,做到更是不简单。。。
这个仅需要具备如下知识:
一、三角函数;
二、CSS和HTML;
三、JS 问好老师,欣赏精彩分享,点赞!{:4_190:} 梦缘 发表于 2023-6-16 16:06
问好老师,欣赏精彩分享,点赞!
{:4_190:} 马黑黑 发表于 2023-6-16 14:34
默认是三个边,可以改
弄不来,{:4_201:} 樵歌 发表于 2023-6-16 17:24
弄不来,
就是边数,你改为4,5,20,36看看 马黑黑 发表于 2023-6-16 14:36
这个仅需要具备如下知识:
一、三角函数;
反正只有黑师整得出来。我溜边儿用用就很不错了{:4_173:} 南无月 发表于 2023-6-16 17:57
反正只有黑师整得出来。我溜边儿用用就很不错了
数学不是体育老师教的一般都木有什么问题 马黑黑 发表于 2023-6-16 18:53
数学不是体育老师教的一般都木有什么问题
{:4_170:}有问题也木有关系,一楼点点就有了 马黑黑 发表于 2023-6-16 14:33
就出裁剪路径的代码
这个确实很神,我电脑里面还做不出来,晕的,果然数学是体育老师教的 小辣椒 发表于 2023-6-16 20:35
这个确实很神,我电脑里面还做不出来,晕的,果然数学是体育老师教的
不会的?女生拿把剪刀胡剪一通不是个事吧 南无月 发表于 2023-6-16 20:10
有问题也木有关系,一楼点点就有了
这个,也许,可能,大概会不是自己所需要的呢?还是得学会自己动手剪一剪 小辣椒 发表于 2023-6-16 20:35
这个确实很神,我电脑里面还做不出来,晕的,果然数学是体育老师教的
随便做一个div,有背景色,然后加入 clip-path 即可:
<style>
.box {
width: 200px;
height: 200px;
background: purple;
clip-path: polygon(200px 100px, 130.902px 195.106px, 19.0983px 158.779px, 19.0983px 41.2215px, 130.902px 4.89435px);
}
</style>
<div class="box"></div>