js+svg绘制七彩虹伞
本帖最后由 马黑黑 于 2023-11-16 07:41 编辑 <br /><br /><style>.papa > p { margin: 10px 0; }
.mama { position: relative; }
.hCode, .hLineNum { padding: 10px; width: 100%; font: normal 16px/20px Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; background: beige; box-sizing: border-box; overflow-x: auto; tab-size: 4; position: absolute; }
.hCode { left: 40px; margin-left: -40px; padding-left: 45px; }
.hLineNum { width: 40px; background: beige; text-align: right; pointer-events: none; color: gray; }
.stage { display: grid; place-items: center; }
.hidden { display: none; }
.rred { padding: 2px 4px; color: red; }
.zs { color: green; }
</style>
<h2>彩虹伞</h2>
<div class="papa">
<p>彩虹伞是彩虹七颜色做成的伞。svg画出这样的伞,首先需要定好颜色,我们采用的是中国传统的赤橙黄绿青蓝紫这七种颜色。下一步制定思路:在一个圆里用七个等腰三角形填充,每一个三角形的等腰边构成的夹角都在圆心处,等腰边夹角的对边用向里的弧形替代。这样的形状需要用 path 元素绘制。以下代码,我们将圆七等分,分别计算每一个三角形等腰边在圆周上的交点的xy坐标,然后用path依次将三角形的三个点连接起来,并给每一个三角形着色,最后形成彩虹伞。伞顶用svg代码另外绘制了一个圆点,它处在圆的正中央。</p>
<div class="mama">
<pre class="hCode"><svg id="ssvg" width="<span class="rred" contenteditable="true">300</span>" height="<span class="rred" contenteditable="true">300</span>" style="border: 1px solid gray;">
<circle id="yuan" cx="150" cy="150" r="5" fill="snow" />
</svg>
<script>
let sepan = () => {
<span class="zs">/* 彩虹颜色数组 */</span>
let colors = ['red','orange','yellow','green','cyan','blue','purple'];
<span class="zs">/* 获取svg宽高 */</span>
let ww = ssvg.getAttribute('width'),
hh = ssvg.getAttribute('height');
<span class="zs">/* 处理svg宽高意外 */</span>
if(ww < 50) ww = 50;
if(hh < 50) hh = 50;
ssvg.setAttribute('width', ww);
ssvg.setAttribute('height', hh);
<span class="zs">/* 圆心坐标和圆半径取svg宽高最短边值 */</span>
let c = r =ww > hh ? hh / 2 : ww / 2;
let a = 360 / 7; <span class="zs">/* 角度 : 圆周七等分 */</span>
yuan.setAttribute('cx',c); <span class="zs">/* 小圆点圆心X坐标 */</span>
yuan.setAttribute('cy',c); <span class="zs">/* 小圆点圆心Y坐标 */</span>
<span class="zs">/* 用 for 循环依次绘制七个三角形 */</span>
for(j = 0; j < 7; j++) {
let color = colors; <span class="zs">/* 取颜色 */</span>
let a1 = a * j; <span class="zs">/* 三角形等腰边1与圆周交点的角度 */</span>
let a2 = a1 + a; <span class="zs">/* 三角形等腰边2与圆周交点的角度 */</span>
<span class="zs">/* 下面使用余弦正弦函数分别获取交点1和交点2的XY坐标值 */</span>
let x1 = c + r * Math.cos(Math.PI / 180 * a1),
x2 = c + r * Math.cos(Math.PI / 180 * a2),
y1 = c + r * Math.sin(Math.PI / 180 * a1),
y2 = c + r * Math.sin(Math.PI / 180 * a2);
<span class="zs">/* 创建svg path元素 */</span>
let path = document.createElementNS('http://www.w3.org/2000/svg', 'path');
<span class="zs">/* 设置 path d 路径属性值 */</span>
path.setAttribute('d', `M ${c} ${c} L${x1} ${y1} A ${c} ${c} 0 0 0 ${x2} ${y2} L${c} ${c}`);
<span class="zs">/* 设置 path 填充颜色 */</span>
path.setAttribute('fill', color);
<span class="zs">/* 将 path 添加到 id="yuan" 的circle的前面(放后面圆点会被覆盖) */</span>
ssvg.insertBefore(path, yuan);
}
};
sepan();<span class="zs">/* 运行绘制彩虹伞函数 */</span>
</script></pre>
<pre class="hLineNum"></pre>
</div>
<p><button class="btnok" type="button" value="运行代码">运行代码</button></p>
<div class="stage"></div>
<p>svg的宽高可以修改,程序将判断宽高尺寸,以最小边为基准绘制图像。如果需要圆环七彩虹色盘,把 A 指令的 0 0 0 改为 0 0 1 便可,当然,这需要与 y1 y2 的正弦取所正负值相配套。</p>
</div>
<script>
let btns = document.querySelectorAll('.btnok'),
stages = document.querySelectorAll('.stage'),
hCodes = document.querySelectorAll('.hCode'),
hLineNums = document.querySelectorAll('.hLineNum'),
mamas = document.querySelectorAll('.mama');
hCodes.forEach((item,key) => {
let lines = hCodes.innerText.trim().split('\n').length;
let str = '';
for(let i = 0; i < lines; i ++) {
str += i + 1 + '\n';
}
hLineNums.innerText = str;
mamas.style.cssText += `height: ${hCodes.offsetHeight + 20}px`;
if(!btns) return;
btns.onclick = () => {
let val = btns.value;
val === '运行代码' ? codeRun(hCodes.innerText, stages) : codeRun('',stages);
btns.value = btns.innerText = val === '运行代码' ? '关闭运行' : '运行代码';
};
});
let codeRun = (str,ele) => {
let reg = /(<script(.*?)>)(.|\n)*?(<\/script>)/g;
let js_str, html_str;
if(str.match(reg) !== null) {
js_str = str.match(reg);
html_str = str.replace(js_str, '').trim();
js_str = js_str.replace(/<[\/]{0,1}script[^>]*>/g,'').trim();
} else {
js_str = '';
html_str = str.trim();
}
ele.innerHTML = html_str;
let myfunc = new Function(js_str);
myfunc();
};
</script>
这个好惊艳,太美了{:4_199:} 取宽高最短边值,这个好理解,如果不是正方形,取短边的一半做半径。
“处理svg宽高意外”这个没懂,也就是当宽高设置得太小时,它自动取50?{:4_203:} 这个A 指令中使用代数,看着好晕乎,其实知道那些和直接输数字是一样的{:4_173:} 红影 发表于 2023-11-16 10:02
取宽高最短边值,这个好理解,如果不是正方形,取短边的一半做半径。
“处理svg宽高意外”这个没懂,也就 ...
对,太小了,或者修改是忘记填写数字了,也给个解决方案,虽然这个方案不是必须的 红影 发表于 2023-11-16 10:25
这个A 指令中使用代数,看着好晕乎,其实知道那些和直接输数字是一样的
代数的好处在于,宽高值改变之后,它依然完好画出七彩虹伞,不必重新一一给各属性修改数值 醉美水芙蓉 发表于 2023-11-16 16:53
黑黑老师太牛了!花伞真漂亮!
感谢支持 马黑黑 发表于 2023-11-16 19:29
代数的好处在于,宽高值改变之后,它依然完好画出七彩虹伞,不必重新一一给各属性修改数值
嗯嗯,知道的,肯定需要这样设置的,只是看着晕而已{:4_173:} 马黑黑 发表于 2023-11-16 12:36
对,太小了,或者修改是忘记填写数字了,也给个解决方案,虽然这个方案不是必须的
哦,原来是这个意思。考虑很周到{:4_204:} 红影 发表于 2023-11-17 23:02
哦,原来是这个意思。考虑很周到
这些,很多时候我一般不会考虑,因为测试者不是恶意使用者,不会设置一个无效的数值(除非出于检测需要)。 马黑黑 发表于 2023-11-18 08:18
这些,很多时候我一般不会考虑,因为测试者不是恶意使用者,不会设置一个无效的数值(除非出于检测需要) ...
能考虑也是好的,可以防止无效数据的出现。 红影 发表于 2023-11-18 13:59
能考虑也是好的,可以防止无效数据的出现。
这在本例不是刚需 马黑黑 发表于 2023-11-18 18:32
这在本例不是刚需
弄出来也是好的,知道有这么个设置。 红影 发表于 2023-11-19 13:40
弄出来也是好的,知道有这么个设置。
这个早知道的 马黑黑 发表于 2023-11-19 19:35
这个早知道的
挺好的。 红影 发表于 2023-11-19 22:55
挺好的。
那就好 马黑黑 发表于 2023-11-19 23:29
那就好
再来看,这小伞好美{:4_199:} 红影 发表于 2023-11-20 16:13
再来看,这小伞好美
你介么一说,肿么俺也觉得美了呢{:4_170:} 马黑黑 发表于 2023-11-20 19:19
你介么一说,肿么俺也觉得美了呢
的确很美,我去试过把 A 指令改001的圆的,就没这么美了{:4_173:}
页:
[1]
2