用clip-path:polygon()绘制多叶草
本帖最后由 马黑黑 于 2023-6-18 10:56 编辑 <br /><br /><style>.mama label, .mama input { margin: 0 6px; }
.mama input { width: 60px; }
.mama p { margin: 10px 0; }
#mydiv {
width: 200px;
height: 200px;
background: tan;
margin: 20px;
}
#msgBox {
width: 100%;
height: 460px;
overflow: auto;
font-size: 12px;
}
</style>
<div class="mama">
<hr />
<p>【说明】叶片系数为奇数时,叶片数=叶片系数;叶片系数为偶数时,叶片数=叶片系数*2。支持浮点数。</p>
<hr />
<p>
<input id="btnReset" type="button" value = "重置" />
<label for="size">尺寸 : </label>
<input id="size" type="number" min="40" max="600" value="200" />
<label for="leaf">叶片系数 : </label>
<input id="leaf" type="number" min="1" max="200" value="2" />
<input id="btnOk" type="button" value = "中" />
</p>
<div id="mydiv"></div>
<p>clip-path代码:</p>
<div id="msgBox"></div>
</div>
<script>
let rosePath = (ww, num) => {
/* 参数——
ww : 正方形尺寸
num: 多叶草系数 奇数时叶片数=系数,偶数时叶片数=系数*2
*/
let points = 360; //圆的等分份数 值越大图案边缘越平滑
let x0 = y0 = r = ww / 2, pathAr = []; //圆心{x0,y0} 半径r 存储数组 pathAr
for (let i = 0; i < points; i ++) {
let angle = i * 2 * Math.PI / points;
let x = x0 - r * Math.cos(angle) * Math.sin(num * angle);
let y = y0 - r * Math.sin(angle) * Math.sin(num * angle);
pathAr.push(x + 'px ' + y + 'px');
}
return `polygon(${pathAr.join(', ')})`;
};
btnOk.onclick = () => {
mydiv.style.width = size.value + 'px';
mydiv.style.height = size.value + 'px';
msgBox.innerText = mydiv.style.clipPath = rosePath(size.value,leaf.value);
};
btnReset.onclick = () => {
mydiv.style.width = '200px';
mydiv.style.height = '200px';
mydiv.style.clipPath = '';
size.value = '200';
leaf.value = '2';
msgBox.innerText = '';
};
</script>
本帖最后由 马黑黑 于 2023-6-18 10:41 编辑
画多叶草,我们需要用到玫瑰线。玫瑰线是一种具有周期性的圆弧曲线,它的规律,如果用直角坐标方程表示,则 xy坐标 可按如下公式求得(公式不止一种):
x=a*sin(nθ)*cos(θ)
y=a*sin(nθ)*sin(θ)
其中,a 为圆的半径,n 是叶片系数(n为奇数时叶片数=n,为偶数时叶片数=n*2),θ 是夹角,sin 和 cos 分别是正弦和余弦函数。
曲线的各点要围绕被裁剪对象的圆心,曲线会穿过圆心,故此,曲线各点的 xy坐标 实践为:
x=x0 - a*sin(nθ)*cos(θ)
y=y0 - a*sin(nθ)*sin(θ)
下来是将圆划分为指定份数的等分,比如 200 个等分,然后用一个 for 循环按照公式把曲线上的每一个点的xy坐标存储起来。假设我们的正方形盒子尺寸为 120 * 120,我们要裁剪出三叶草 :
<style>
#mybox {
width: 120px;
height: 120px;
background: pink;
margin: 20px;
}
</style>
<div id="mybox"></div>
<script>
let x0 = y0 = a = 60, pathAr = [];
for(let i = 0; i < 200; i ++) {
let angle = i * 2 * Math.PI / 200;
let x = 60 - a * Math.sin(3 * angle) * Math.cos(angle);
let y = 60 - a * Math.sin(3 * angle) * Math.sin(angle);
pathAr.push(x + 'px ' + y + 'px');
}
mybox.style.clipPath = 'polygon(' + pathAr.join(', ') + ')';
</script>代码中,夹角 angle 的计算是关键。我们将圆弄成 200 个等分,即 2π / 200,然后在每一等分上确定图案曲线所在点的夹角 θ(即angle) 则为 i * 2 * Math.PI / 200,这是计算出该点的xy坐标的依据。
本帖最后由 马黑黑 于 2023-6-18 10:57 编辑
一楼代码<style>
.mama label, .mama input { margin: 0 6px; }
.mama input { width: 60px; }
.mama p { margin: 10px 0; }
#mydiv {
width: 200px;
height: 200px;
background: tan;
margin: 20px;
}
#msgBox {
width: 100%;
height: 460px;
overflow: auto;
font-size: 12px;
}
</style>
<div class="mama">
<hr />
<p>【说明】叶片系数为奇数时,叶片数=叶片系数;叶片系数为偶数时,叶片数=叶片系数*2。支持浮点数。</p>
<hr />
<p>
<input id="btnReset" type="button" value = "重置" />
<label for="size">尺寸 : </label>
<input id="size" type="number" min="40" max="600" value="200" />
<label for="leaf">叶片系数 : </label>
<input id="leaf" type="number" min="1" max="200" value="2" />
<input id="btnOk" type="button" value = "中" />
</p>
<div id="mydiv"></div>
<p>clip-path代码:</p>
<div id="msgBox"></div>
</div>
<script>
let rosePath = (ww, num) => {
/* 参数——
ww : 正方形尺寸
num: 多叶草系数 奇数时叶片数=系数,偶数时叶片数=系数*2
*/
let points = 360; //圆的等分份数 值越大图案边缘越平滑
let x0 = y0 = r = ww / 2, pathAr = []; //圆心{x0,y0} 半径r 存储数组 pathAr
for (let i = 0; i < points; i ++) {
let angle = i * 2 * Math.PI / points;
let x = x0 - r * Math.cos(angle) * Math.sin(num * angle);
let y = y0 - r * Math.sin(angle) * Math.sin(num * angle);
pathAr.push(x + 'px ' + y + 'px');
}
return `polygon(${pathAr.join(', ')})`;
};
btnOk.onclick = () => {
mydiv.style.width = size.value + 'px';
mydiv.style.height = size.value + 'px';
msgBox.innerText = mydiv.style.clipPath = rosePath(size.value,leaf.value);
};
btnReset.onclick = () => {
mydiv.style.width = '200px';
mydiv.style.height = '200px';
mydiv.style.clipPath = '';
size.value = '200';
leaf.value = '2';
msgBox.innerText = '';
};
</script>
我的天,这个路径好复杂啊{:4_173:} 去一个个试了一下,单数的叶瓣和数字相符,双数的叶瓣是加倍的。{:4_203:} 在css-doodle里就是把这复杂的计算过程和路径给省了吧,直接用公式和调用script就出来了。
看看黑黑原始是如何制作的,可以对那个过程有更深的了解了,真棒{:4_199:} 黑黑留2层够用不?如果不够用,我把我的回帖删掉{:4_173:} {:4_199:}支持浮点数,可以有各种不规则形状。。 红影 发表于 2023-6-18 09:41
我的天,这个路径好复杂啊
原理相对不复杂,生成的路径很长 红影 发表于 2023-6-18 09:42
去一个个试了一下,单数的叶瓣和数字相符,双数的叶瓣是加倍的。
有说明的,看一楼和二楼 红影 发表于 2023-6-18 09:46
在css-doodle里就是把这复杂的计算过程和路径给省了吧,直接用公式和调用script就出来了。
看看黑黑原始是 ...
css-doodle做了更为复杂的封装,我这个不能和它比的。我这里,仅是展现以下polygon的强大,它可以以很多的点做成自己想要的图案。 南无月 发表于 2023-6-18 10:16
支持浮点数,可以有各种不规则形状。。
细心,看到我的说明 红影 发表于 2023-6-18 09:47
黑黑留2层够用不?如果不够用,我把我的回帖删掉
留多了{:4_170:} 今天是不是我的速度问题,我点击了重置没有效果出来 马黑黑 发表于 2023-6-18 09:26
画多叶草,我们需要用到玫瑰线。玫瑰线是一种具有周期性的圆弧曲线,它的规律,如果用直角坐标方程表示,则 ...
这个电脑预览看见了 马黑黑 发表于 2023-6-18 10:37
原理相对不复杂,生成的路径很长
是的,原理倒还好理解{:4_204:} 马黑黑 发表于 2023-6-18 10:42
有说明的,看一楼和二楼
看到了啊,前面我来的时候,那些还没弄好{:4_173:} 马黑黑 发表于 2023-6-18 09:26
一楼代码
看见了源码数据出来了 马黑黑 发表于 2023-6-18 10:44
css-doodle做了更为复杂的封装,我这个不能和它比的。我这里,仅是展现以下polygon的强大,它可以以很多 ...
道理应该是相通的,学习一下这个特别好{:4_199:} 马黑黑 发表于 2023-6-18 10:56
留多了
那就好,我就不用去删自己的了{:4_173:}