随机点绘制多边形的初始尝试
我开始迷上画多边形了,可是做出来效果不怎么样,总有那么点儿小瑕疵。咱们能否试试把点数调成可变的,这样每个点的膨胀程度就能差不多一样。但是有时候随机选的点会过于集中,这样会让交汇处变得有点乱糟糟。那咱们该怎么办?那就是找个方法让整个画面看起来更舒服,更好看!
优化连线方式:按角度连接点
咱试试看哈。那杂七杂八的交叉线怎么办?找个稳妥的地方算算每根线跟这地方的角度,然后一口气画个直线就成了。虽然还是有些交叉线在,但是肯定比以前强多了!
尝试优化方案
我用了Math.abs来算正角度。找到了连起来后最小夹角的位置,不过结果不是很理想。总不能老是避开交叉线?还是得找一个实用点儿的办法。
let balls = []; let ballNum = 6; let firstBall = null; while(ballNum--) { let ball = new Ball(20, parseColor(Math.random() * 0xffffff)) ball.x = Math.random() * width; ball.y = Math.random() * height; balls.push(ball) if (!firstBall) { firstBall = ball ball.angle = 0 } else { const dx = ball.x - firstBall.x, dy = ball.y - firstBall.y; ball.angle = Math.atan2(dy, dx); } } // 尝试让球连线是一个正多边形 balls = balls.sort((ballA, ballB) => { return ballA.angle - ballB.angle })
基于中心点旋转连接
找出多边形的重心很关键!然后根据这些点和重心角度来画线,搞懂就好。但有时候算法要求点要按特定顺序排列,那就稍显麻烦了。
X轴两极点分割
网上学的画不规则多边形很简单,首先用线把这些点连起来就行了。记住,上链时数值要逐渐变小,下链时得变成大的(顺着或者反方向转都可以)。掌握这样的技巧,你也能轻松画出各种变化的图形!
严格按照算法实现
这个办法超好用!只要找出两点间的极点位置,就知道它们之间夹角大小!然后,就可以轻轻松松判定两点是不是处于同一直线上,或者分别位于不同直线上。这个办法超级直观明了,就算遇到复杂的十字路口问题也能搞定!
代码实现与效果展示
我们给画图软件加个改进算法,顺手儿就把逆时针画多边形那个困扰弄没了。这样之后画出的线更美,也没了谁被谁挡住的问题!
其他优化可能性探讨
别只用那招儿,试试换个排列线条的办法。调整后,图形看起来会更酷炫哒!胆子大点儿,新的尝试可能让你发现更棒的优化途径
结语与展望
搞定Canvas画框真是要有一定的数学和编程水平。看完这篇文章后,以后做项目就能轻松用学到的东西找到更好的画图办法。以后还会分享更多有意思的Canvas作品!
let balls = []; let tempBalls = []; let ballNum = 6; let isDragingBall = false; while(ballNum--) { let ball = new Ball(10, parseColor(Math.random() * 0xffffff)) ball.x = Math.random() * width; ball.y = Math.random() * height; tempBalls.push(ball) } // 让点按X轴升序排序 tempBalls = tempBalls.sort((ballA, ballB) => { return ballA.x - ballB.x }) // 找X轴左右极点 let firstBall = tempBalls[0], lastBall = tempBalls[tempBalls.length -1]; let smallXBalls = tempBalls.filter(ball => ball.x === firstBall.x), bigXBalls = tempBalls.filter(ball => ball.x === lastBall.x) // 处理左右极点有多个的情况 if (smallXBalls.length > 1) { smallXBalls.sort((ballA, ballB) => { return ballB.y - ballA.y }) } if (bigXBalls.length > 1) { bigXBalls.sort((ballA, ballB) => { return ballB.y - ballA.y }) } firstBall = smallXBalls[0] lastBall = bigXBalls[0] // 获得极点连线的角度 let splitLineAngle = Math.atan2(lastBall.y - firstBall.y, lastBall.x - firstBall.x); let upperBalls = [], lowerBalls = []; // 所有其他点跟firstBall计算角度 // 大于splitLineAngle的都是下链 // 其他是上链 tempBalls.forEach(ball => { if (ball === firstBall || ball === lastBall) { return false } let angle = Math.atan2(ball.y - firstBall.y, ball.x - firstBall.x); if (angle > splitLineAngle) { lowerBalls.push(ball) } else { upperBalls.push(ball) } }) // 处理X轴相同情况的排序 lowerBalls = lowerBalls.sort((ballA, ballB) => { if (ballA.x !== ballB.x) { return ballA.x - ballB.x } return ballB.y - ballA.y }) upperBalls = upperBalls.sort((ballA, ballB) => { if (ballA.x !== ballB.x) { return ballB.x - ballA.x } return ballB.y - ballB.x }) // 逆时针连接所有的点 balls = [firstBall].concat(lowerBalls, [lastBall], upperBalls) balls = balls.map((ball, i) => { ball.text = i + 1; return ball })
。
评论0