如何在canvas里面基于随机点绘制一个多边形
这篇文章主要介绍了canvas里面如何基于随机点绘制一个多边形的方法的相关资料,内容挺不错的,现在分享给大家,也给大家做个参考。
起因
今天在学习《HTML5+Javascript动画基础》这本书的时候,在第八章的第三节讲到如何用三个弹簧连接三个点来做拉伸运动。
在做完例子之后,就想到如果是四个点,五个点,怎么样。
就改写了一下代码,把点的数目变量化。最终的效果是能实现各个点最终的拉伸运动到平衡,可是点之间的连线不是很好看,有些是交叉的。
于是就想着能不能优化这一块。
旋转连线
前面例子里面的点,都是随机位置,所以连线不可控。所以想先从这块着手。
先以某一个点为参照点,获得其他点相对于这个点的角度。
然后按照角度从小到大的去连接这些点,这样就能画出一个正常的多边形了。
大致实现代码如下:
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 })
这样在最后绘制连线的时候,遍历数组就能按照角度从小到大来绘制了。
效果如下:
这样是能极大的减少交叉线的情况,可还是无法完全避免。
接下来,想尝试优化这个方案,比如angle用Math.abs来取正,或者每一个点都找夹角最小的点来连线。可是结果都不行,无法避免交叉线。
基于中心点旋转
后面又想到一个思路,如果能确定多边形的中心点,那么分别计算所有点相对于中心点的夹角,就能以顺时针或者逆时针来连接这些点。
可是在网上找了半天,所有点算法里面,都是要求有一系列按某个时针顺序排列的点。
可是如果我有这些点,就已经能绘制多边形了。只好放弃
X轴两极点分割
无奈之下只好找Google,然后就发现了知乎上的一个答案挺好的: 如何将平面上无序的一组点连成一个简单多边形?
具体算法描述,大家看那个答案就好,我就不赘述了。
不过在连接上链和下链的时候,其实只要保证上链是X轴降序连接,下链是X轴升序连接即可(以逆时针方向绘制)。至于X轴相同的点,不管是优先Y轴大的还是小的都可以。
实现的时候,是严格按照答案里面的算法实现的。
在判断一个点是属于上链还是下链的时候,一开始想的是基于两点确定直线的函数方程,再引入点的坐标来计算。不过后面想到,所有的点都以最左边的极点来计算斜角,然后根据角度大小来划分,视觉上更好理解。
大致代码如下:
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 })
最终返回的balls,就是按逆时针排序的多边形的点了。
效果如下:
各个球的内部状态如下:
以上就是本文的全部内容,希望对大家的学习有所帮助,更多相关内容请关注PHP中文网!
相关推荐:
使用html5
canvas封装一个echarts实现不了的饼图
以上是如何在canvas里面基于随机点绘制一个多边形的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

Video Face Swap
使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

ppt在很多领域和工作中被广泛使用,教育类、建筑类等等的使用更是普遍。提到建筑ppt,肯定我们首先想到的是一些建筑类图纸的呈现,如果我们没有使用专业图纸绘画软件,能不能直接绘制简单的建筑平面图呢?其实,这里,我们是可以完成操作的,下边,我们就绘制一个比较简单的平面图,给大家一个思路,希望大家能够在这个思路下完成更好的平面图绘制。1、首先,我们双击打开桌面上ppt软件,单击新建演示空白文档。2、我们在菜单栏找到插入→形状→矩形。3、绘制矩形完成,随后,双击图形,我们修改填充颜色类型,这里我们可以修

Aheptagonalnumberisanumberwhichcanberepresentedasaheptagon.Aheptagonisapolygonwith7sides.Aheptagonalnumbercanberepresentedasacombinationofsuccessivelayersofheptagon(7-sidedpolygon).Heptagonalnumbercanbebetterexplainedwiththebelowfigures.第一个七边形数是1。因此,

如何用Python绘制3D地理图表概述:绘制3D地理图表可以帮助我们更直观地理解地理数据和空间分布。Python作为一种功能强大且易于使用的编程语言,提供了许多库和工具,可用于绘制各种类型的地理图表。在本文中,我们将学习如何使用Python编程语言和一些流行的库,如Matplotlib和Basemap,来绘制3D地理图表。环境准备:在开始之前,我们需要确保已

五分钟学会用Python绘制树状图和雷达图在数据可视化中,树状图和雷达图是两种常用的图表形式。树状图用于展示层级结构,而雷达图则用于比较多个维度的数据。本文将介绍如何使用Python绘制这两种图表,并提供具体的代码示例。一、绘制树状图Python中有多个库可以用于绘制树状图,如matplotlib和graphviz。下面以使用matplotlib库为例,演示

探索Canvas框架:了解常用的Canvas框架有哪些,需要具体代码示例引言:Canvas是HTML5中提供的一个绘图API,通过它我们可以实现丰富的图形和动画效果。为了提高绘图的效率和便捷性,许多开发者开发了不同的Canvas框架。本文将介绍一些常用的Canvas框架,并提供具体代码示例,以帮助读者更深入地了解这些框架的使用方法。一、EaselJS框架Ea

html2canvas的版本有html2canvas v0.x、html2canvas v1.x等。详细介绍:1、html2canvas v0.x,这是html2canvas的早期版本,目前最新的稳定版本是v0.5.0-alpha1。它是一个成熟的版本,已经被广泛使用,并且在许多项目中得到了验证;2、html2canvas v1.x,这是html2canvas的新版本。

uniapp实现如何使用canvas绘制图表和动画效果,需要具体代码示例一、引言随着移动设备的普及,越来越多的应用程序需要在移动端展示各种图表和动画效果。而uniapp作为一款基于Vue.js的跨平台开发框架,提供了使用canvas绘制图表和动画效果的能力。本文将介绍uniapp如何使用canvas来实现图表和动画效果,并给出具体的代码示例。二、canvas

如何用Python绘制动画图表Python作为一种功能强大的编程语言,可以用于各种数据可视化和图表绘制。其中,绘制动画图表可以让数据更加生动有趣。本文将介绍如何使用Python绘制动画图表,并提供具体的代码示例。首先,我们需要安装matplotlib库,这是Python中最常用的图表绘制库之一。在终端中运行以下命令安装matplotlib:pipinsta
