马黑黑 发表于 2023-6-18 09:26

用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 09:26

本帖最后由 马黑黑 于 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 09:26

本帖最后由 马黑黑 于 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>

红影 发表于 2023-6-18 09:41

我的天,这个路径好复杂啊{:4_173:}

红影 发表于 2023-6-18 09:42

去一个个试了一下,单数的叶瓣和数字相符,双数的叶瓣是加倍的。{:4_203:}

红影 发表于 2023-6-18 09:46

在css-doodle里就是把这复杂的计算过程和路径给省了吧,直接用公式和调用script就出来了。
看看黑黑原始是如何制作的,可以对那个过程有更深的了解了,真棒{:4_199:}

红影 发表于 2023-6-18 09:47

黑黑留2层够用不?如果不够用,我把我的回帖删掉{:4_173:}

南无月 发表于 2023-6-18 10:16

{:4_199:}支持浮点数,可以有各种不规则形状。。

马黑黑 发表于 2023-6-18 10:37

红影 发表于 2023-6-18 09:41
我的天,这个路径好复杂啊

原理相对不复杂,生成的路径很长

马黑黑 发表于 2023-6-18 10:42

红影 发表于 2023-6-18 09:42
去一个个试了一下,单数的叶瓣和数字相符,双数的叶瓣是加倍的。

有说明的,看一楼和二楼

马黑黑 发表于 2023-6-18 10:44

红影 发表于 2023-6-18 09:46
在css-doodle里就是把这复杂的计算过程和路径给省了吧,直接用公式和调用script就出来了。
看看黑黑原始是 ...

css-doodle做了更为复杂的封装,我这个不能和它比的。我这里,仅是展现以下polygon的强大,它可以以很多的点做成自己想要的图案。

马黑黑 发表于 2023-6-18 10:45

南无月 发表于 2023-6-18 10:16
支持浮点数,可以有各种不规则形状。。

细心,看到我的说明

马黑黑 发表于 2023-6-18 10:56

红影 发表于 2023-6-18 09:47
黑黑留2层够用不?如果不够用,我把我的回帖删掉

留多了{:4_170:}

小辣椒 发表于 2023-6-18 14:25

今天是不是我的速度问题,我点击了重置没有效果出来

小辣椒 发表于 2023-6-18 14:26

马黑黑 发表于 2023-6-18 09:26
画多叶草,我们需要用到玫瑰线。玫瑰线是一种具有周期性的圆弧曲线,它的规律,如果用直角坐标方程表示,则 ...

这个电脑预览看见了

红影 发表于 2023-6-18 14:26

马黑黑 发表于 2023-6-18 10:37
原理相对不复杂,生成的路径很长

是的,原理倒还好理解{:4_204:}

红影 发表于 2023-6-18 14:27

马黑黑 发表于 2023-6-18 10:42
有说明的,看一楼和二楼

看到了啊,前面我来的时候,那些还没弄好{:4_173:}

小辣椒 发表于 2023-6-18 14:27

马黑黑 发表于 2023-6-18 09:26
一楼代码

看见了源码数据出来了

红影 发表于 2023-6-18 14:28

马黑黑 发表于 2023-6-18 10:44
css-doodle做了更为复杂的封装,我这个不能和它比的。我这里,仅是展现以下polygon的强大,它可以以很多 ...

道理应该是相通的,学习一下这个特别好{:4_199:}

红影 发表于 2023-6-18 14:28

马黑黑 发表于 2023-6-18 10:56
留多了

那就好,我就不用去删自己的了{:4_173:}
页: [1] 2 3 4 5
查看完整版本: 用clip-path:polygon()绘制多叶草