改进版svg太阳花图案在线制作
<style>.papa { margin: auto; width: 700px; display: grid; place-items: center; }
.papa svg { margin: 10px 0; width: 400px; height: 400px; }
.papa output { margin: 10px 0; max-height: 100px; overflow-y: auto; }
.set { display: flex; align-items: center; gap: 8px; }
</style>
<div class="papa">
<p class="set">
<svg>
<polygon id="poly" points="400.00 200.00, 155.50 394.99, 19.81 113.22, 324.70 43.63, 324.70 356.37, 19.81 286.78, 155.50 5.01" fill-rule="evenodd" fill="red" stroke="green" stroke-width="2" />
</svg>
</p>
<p class="set">
<label for="angRng">设置顶点数: </label>
<input id="angRng" type="range" min="4" max="300" step="1" value="7" />
<output id="angNum">7</output>
<label> 【 填充模式 : </label>
<input id="f1" type="radio" name="fill" value="" />
<label for="f1">无</label>
<input id="f2" type="radio" name="fill" value="nonzero" />
<label for="f2">nonzero</label>
<input id="f3" type="radio" name="fill" value="evenodd" checked />
<label for="f3">evenodd 】</label>
</p>
<output id="pointscode">操作方法:① 拖动滑杆选择顶点数 ② 选择填充模式</output>
</div>
<script>
let addStep = (num) => {
/*连线偏移算法 :
偶数中被 4 整除的无需偏移 +0
奇数分两种情形:
① 减去 9 后被6整除的 -1
② 减去 15 后被 30 整除的 +1
③ 不符合上述两个条件的 +0
*/
let res = 0;
if(num % 2 === 0) {
res = num % 4 != 0 ? -1 : 0;
}else{
res = (num - 9) % 6 === 0 ? -1 : 0;
if((num - 15) % 30 === 0)res = 1;
}
return res;
};
/* 获取圆周上均分的点坐标 */
let getCircPoints = (num) => {
let x = 200, y = 200, r= 200, angle = 0;
let step = 2 * Math.PI / num, start = angle / 180 * Math.PI;
let points = [];
for (let j = 0; j < num; j++) {
let a = step * j + start;
let px = (Math.cos(a) * r + x).toFixed(2), py = (Math.sin(a) * r + y).toFixed(2);
points.push(px + ' ' + py);
}
return points;
}
/* 生成 polygon 的 points 属性值 */
let mkStar = (num) => {
let ar = getCircPoints(num), datas = [];
let step = Math.ceil((ar.length - 3) / 2) + addStep(num);
for(i = 0; i < ar.length; i++) {
let idx = (i * step) % ar.length;
datas.push(ar);
}
return datas.join(', ');
};
angRng.oninput = () => {
let points = mkStar(angRng.value * 1);
poly.setAttribute('points', points);
pointscode.innerText = 'points="' + points + '"';
angNum.innerText = angRng.value;
};
let fills = document.getElementsByName('fill');
fills.forEach((item,key) => {
item.onclick = () => {
let fillcolor = key > 0 ? 'red' : 'none';
poly.setAttribute('fill',fillcolor);
poly.setAttribute('fill-rule',item.value);
};
});
</script>
采用自己的思路,全新编写连线算法,总体实现方式更干净利落。
改版后,太阳花的顶点数理论上支持 ≥ 4 的任意顶点数,突破顶点数要被4整除的局限。一楼提供最大300个顶点数,实际上太多的顶点数连线会非常密集,到一定数值时图案会是一个圆。
不知道新算法是否经得起考验,若有问题,请及时反馈,谢谢。 附:一楼完整代码
<style>
.papa { margin: auto; width: 700px; display: grid; place-items: center; }
.papa svg { margin: 10px 0; width: 400px; height: 400px; }
.papa output { margin: 10px 0; max-height: 100px; overflow-y: auto; }
.set { display: flex; align-items: center; gap: 8px; }
</style>
<div class="papa">
<p class="set">
<svg>
<polygon id="poly" points="400.00 200.00, 155.50 394.99, 19.81 113.22, 324.70 43.63, 324.70 356.37, 19.81 286.78, 155.50 5.01" fill-rule="evenodd" fill="red" stroke="green" stroke-width="2" />
</svg>
</p>
<p class="set">
<label for="angRng">设置顶点数: </label>
<input id="angRng" type="range" min="4" max="300" step="1" value="7" />
<output id="angNum">7</output>
<label> 【 填充模式 : </label>
<input id="f1" type="radio" name="fill" value="" />
<label for="f1">无</label>
<input id="f2" type="radio" name="fill" value="nonzero" />
<label for="f2">nonzero</label>
<input id="f3" type="radio" name="fill" value="evenodd" checked />
<label for="f3">evenodd 】</label>
</p>
<output id="pointscode">操作方法:① 拖动滑杆选择顶点数 ② 选择填充模式</output>
</div>
<script>
let addStep = (num) => {
/*连线偏移算法 :
偶数中被 4 整除的无需偏移 +0
奇数分两种情形:
① 减去 9 后被6整除的 -1
② 减去 15 后被 30 整除的 +1
③ 不符合上述两个条件的 +0
*/
let res = 0;
if(num % 2 === 0) {
res = num % 4 != 0 ? -1 : 0;
}else{
res = (num - 9) % 6 === 0 ? -1 : 0;
if((num - 15) % 30 === 0)res = 1;
}
return res;
};
/* 获取圆周上均分的点坐标 */
let getCircPoints = (num) => {
let x = 200, y = 200, r= 200, angle = 0;
let step = 2 * Math.PI / num, start = angle / 180 * Math.PI;
let points = [];
for (let j = 0; j < num; j++) {
let a = step * j + start;
let px = (Math.cos(a) * r + x).toFixed(2), py = (Math.sin(a) * r + y).toFixed(2);
points.push(px + ' ' + py);
}
return points;
}
/* 生成 polygon 的 points 属性值 */
let mkStar = (num) => {
let ar = getCircPoints(num), datas = [];
let step = Math.ceil((ar.length - 3) / 2) + addStep(num);
for(i = 0; i < ar.length; i++) {
let idx = (i * step) % ar.length;
datas.push(ar);
}
return datas.join(', ');
};
angRng.oninput = () => {
let points = mkStar(angRng.value * 1);
poly.setAttribute('points', points);
pointscode.innerText = 'points="' + points + '"';
angNum.innerText = angRng.value;
};
let fills = document.getElementsByName('fill');
fills.forEach((item,key) => {
item.onclick = () => {
let fillcolor = key > 0 ? 'red' : 'none';
poly.setAttribute('fill',fillcolor);
poly.setAttribute('fill-rule',item.value);
};
});
</script>
黑黑老师又有创新了,俺不懂,等着看精彩作业{:4_187:} 千羽 发表于 2023-11-5 14:43
黑黑老师又有创新了,俺不懂,等着看精彩作业
这个是对svg polygon标签的进一步研究,不见得一定得和做帖子有关 醉美水芙蓉 发表于 2023-11-5 16:56
欣赏老师新作品改进版!
这个版本,一是更换了算法,二是支持更多的顶边尖角数 原来连线的方式是不同的,怪不得得到的感觉不同{:4_173:} 连线偏移算法 :
偶数中被 4 整除的无需偏移 +0
奇数分两种情形:
① 减去 9 后被6整除的 -1
② 减去 15 后被 30 整除的 +1
③ 不符合上述两个条件的 +0
这个连线方式很复杂,先看偶数,偶数就一个情况,能被4整除或不能。
能被4整除的就按规则不偏移,那不能整除的是怎么偏移的?看了看好像使用了前一个能被4整除的方式。
再看看奇数的,看起来到一定的数值之后才能完全去遵守。 点的获取很简单,只是平分圆,如何连线才是关键啊{:4_187:} 能从4的整倍数点子的连线方式,研究出来适应所有点数的连线方式,这个太厉害了{:4_199:}
虽然对为什么区分奇偶数做这样的连线排布还没懂,但是信了黑黑说的代码跟数学有密不可分的关系,这里面一定是对应着数学规律的{:4_199:} 红影 发表于 2023-11-5 17:22
原来连线的方式是不同的,怪不得得到的感觉不同
先前的版本是别人的算法,有四的倍数的约束。现在是自己的算法,支持不被4整除的顶点数 红影 发表于 2023-11-5 17:33
连线偏移算法 :
偶数中被 4 整除的无需偏移 +0
奇数分两种情形:
圆周上点对点连线,当都是连接相邻点是,得到的是多边形;要想得到太阳花图案,需要按一定规则错开连接,这里面就涉及到算法的设计。
圆周上N个点如何去连接,总得有个开头,我们从最右边的点开始,它连接的下一个点算法是:
(N-3)/ 2
上式,向上取整。
然后从下一个点开始,继续按上述算式找下一个点,直到所有的点找完。
期间,还分支处理一些情况,凡不被 4 整除的,如果纯粹使用上面的式子,它们会重复找点,得到的结果就不是 N 个顶点,因为连线会重复。这需要做具体处理,需要一定的数学洞察力。 红影 发表于 2023-11-5 17:34
点的获取很简单,只是平分圆,如何连线才是关键啊
重点在连线 红影 发表于 2023-11-5 17:39
能从4的整倍数点子的连线方式,研究出来适应所有点数的连线方式,这个太厉害了
虽然对为什么区 ...
数学抽象但非常实用,它被广泛应用于各个领域。 不懂!我就是来看个热闹!{:5_102:} 亦是金 发表于 2023-11-5 20:19
不懂!我就是来看个热闹!
{:4_191:} 越来越精美了,黑黑脑细胞真多{:4_199:} 马黑黑 发表于 2023-11-5 17:46
先前的版本是别人的算法,有四的倍数的约束。现在是自己的算法,支持不被4整除的顶点数
是的,这是你自己的研究成果{:4_187:} 马黑黑 发表于 2023-11-5 17:59
圆周上点对点连线,当都是连接相邻点是,得到的是多边形;要想得到太阳花图案,需要按一定规则错开连接, ...
所以如何取点很有讲究{:4_187:}