用clip-path:polygon()内切正多边形
<style>#mydiv {
width: 200px;
height: 200px;
background: rebeccapurple;
border-radius: 50%;
}
.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" />
<label for="numThick">边厚:</label>
<input id="numThick" type="number" value="10" min="5" max="40" />
<input id="btnOk" type="button" value="裁剪" />
</p>
<div id="mydiv"></div>
<div id="msgBox"></div>
</div>
<script>
let clipBox = (xx,points,thick) => {
if(points < 3) points = 3;
let x0 = y0 = r = xx / 2, pointsAr = [`200px 0, 0 0, 0 ${xx}px, ${xx}px ${xx}px, ${xx}px ${xx/2}px`];
for(let i = 0; i <= points; i ++) {
let hudu = Math.PI / 180 * 360 / points * i;
let x1 = x0 + Math.cos(hudu) * (r - thick), y1 = y0 + Math.sin(hudu) * (r - thick);
pointsAr.push(x1 + 'px ' + y1 + 'px');
}
pointsAr.push(`${xx}px ${xx/2}px`);
pointsAr.push(`${xx}px 0px`);
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,40,600);
numThick.onchange = () => limit(numThick,5,40);
btnOk.onclick = () => {
mydiv.style.width = numLen.value + 'px';
mydiv.style.height = numLen.value + 'px';
mydiv.style.clipPath = clipBox(numLen.value, numPoint.value, numThick.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';
numThick.value = '10';
msgBox.innerText = '';
}
</script>
代码
<style>
#mydiv {
width: 200px;
height: 200px;
background: rebeccapurple;
border-radius: 50%;
}
.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" />
<label for="numThick">边厚:</label>
<input id="numThick" type="number" value="10" min="5" max="40" />
<input id="btnOk" type="button" value="裁剪" />
</p>
<div id="mydiv"></div>
<div id="msgBox"></div>
</div>
<script>
let clipBox = (xx,points,thick) => {
if(points < 3) points = 3;
let x0 = y0 = r = xx / 2, pointsAr = [`200px 0, 0 0, 0 ${xx}px, ${xx}px ${xx}px, ${xx}px ${xx/2}px`];
for(let i = 0; i <= points; i ++) {
let hudu = Math.PI / 180 * 360 / points * i;
let x1 = x0 + Math.cos(hudu) * (r - thick), y1 = y0 + Math.sin(hudu) * (r - thick);
pointsAr.push(x1 + 'px ' + y1 + 'px');
}
pointsAr.push(`${xx}px ${xx/2}px`);
pointsAr.push(`${xx}px 0px`);
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,40,600);
numThick.onchange = () => limit(numThick,5,40);
btnOk.onclick = () => {
mydiv.style.width = numLen.value + 'px';
mydiv.style.height = numLen.value + 'px';
mydiv.style.clipPath = clipBox(numLen.value, numPoint.value, numThick.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';
numThick.value = '10';
msgBox.innerText = '';
}
</script>
本帖最后由 马黑黑 于 2023-6-17 12:26 编辑
核心思路:
先从外围起剪,到 {100%, 50%} 处往里水平切厚度单位的距离,然后里面的切法交给 for 语句完成,回到往里切厚度单位的那个点后,沿原路返回 {100%, 50%} 处,再裁剪外围尚未裁剪的部分并回到起点。 需要突破本例的一些限定的,请在本地测试时修改如下JS语句:
numPoint.onchange = () => limit(numPoint,3,360); /* 边数限制 */
numLen.onchange = () => limit(numLen,40,600); /* 正方形尺寸 */
numThick.onchange = () => limit(numThick,5,40); /* 预留厚度 */ 脚本边数可以使用浮点数,可以试试 这个厉害了,可以任意得到规定范围里的边数和边厚的镂空多边形,还是返回路径。太赞了{:4_199:} 这个用对应角度来找到一个个多边形的点,这思路绝对太棒了{:4_199:} 又开发了一个特别好的在线工具,黑黑厉害{:4_199:} 又去看了看前面裁剪多边形的帖子,昨天回来喝多了酒,都没仔细去理解{:4_173:} 问好老师,欣赏精彩佳作,谢谢分享!{:4_191:} 梦缘 发表于 2023-6-17 16:54
问好老师,欣赏精彩佳作,谢谢分享!
{:4_190:} 红影 发表于 2023-6-17 15:54
这个厉害了,可以任意得到规定范围里的边数和边厚的镂空多边形,还是返回路径。太赞了
内镂空前几天做过的。我的这个方法比张鑫旭等大佬们的方法要好得多,不过我没有和他们做过交流。 红影 发表于 2023-6-17 15:56
这个用对应角度来找到一个个多边形的点,这思路绝对太棒了
因为不想额外处理 for 语句,就是不想重新排序角度,都从 0 夹角开始,所以,所有的最大化多边形的切割起点,都从三点钟方向开始。 红影 发表于 2023-6-17 16:03
又去看了看前面裁剪多边形的帖子,昨天回来喝多了酒,都没仔细去理解
这个理解起来并不难。程序代码中,重点要消化的是polygon路径的设计与计算。 红影 发表于 2023-6-17 15:57
又开发了一个特别好的在线工具,黑黑厉害
这个,严格意义上讲,还不能算式工具把,就是玩玩,或许有用,弄个切割路径还行的 全自动的切割机。。。好用。。。{:4_187:} 南无月 发表于 2023-6-17 17:27
全自动的切割机。。。好用。。。
剪刀好切啥都顺 马黑黑 发表于 2023-6-17 17:28
剪刀好切啥都顺
花黑牌的是名牌儿。。{:4_170:}杠杠的 南无月 发表于 2023-6-17 17:42
花黑牌的是名牌儿。。杠杠的
注资六毛 马黑黑 发表于 2023-6-17 16:57
内镂空前几天做过的。我的这个方法比张鑫旭等大佬们的方法要好得多,不过我没有和他们做过交流。
这个能弄出任意边数的镂空呢{:4_199:}