调用paintSpiral函数进行绘制,红色圆形标记点是我们获取的放置坐标,用黑线连接放置点,用于看清螺线的形状(实际使用时只需要放置点即可)。
// 画布宽高 const CANVAS_SIZE = [500, 500] // 绘制螺线 const getPosition = archimedeanSpiral(CANVAS_SIZE, { step: 0.1, b: 1 }) paintSpiral(CANVAS_SIZE, getPosition, { showIndex: false })为了方便观察,增大螺距与步长,绘制一个比较稀疏的螺线,同时标记出点的放置顺序。
const getPosition = archimedeanSpiral(CANVAS_SIZE, { step: 1, b: 10 }) paintSpiral(CANVAS_SIZE, getPosition, { showIndex: true })可以看到将螺距调大后每一圈的螺线相距的更远了,而调整步长后每一圈取的标记点数量变少了。接下来尝试将文字按照放置点顺序进行摆放。
实现一个drawWords函数来根据布局函数放置词汇。
/** * 根据阿基米德螺线绘制词汇 * @param {*} data 词汇数据 * @param {*} getPosition 布局函数 */ const drawWords = (data, size, getPosition, ) => { let t = 0 const { context, canvas } = createCanvas(size[0], size[1]) data.forEach((word, index) => { const [dx, dy] = getPosition(t += 1) word.x = size[0] / 2 + dx word.y = size[1] / 2 + dy word.fontSize = Math.floor(word.fontSize / 2) word.text = `${index}-${word.text}` drawText(context, word) }) document.body.appendChild(canvas) }绘制螺线与词汇
// 绘制一遍螺线用于对比 const getPosition = archimedeanSpiral(CANVAS_SIZE, { step: 1, b: 10 }) paintSpiral(CANVAS_SIZE, getPosition, { showIndex: true }) // 绘制单词, 这里的data为文章开头的数据 drawWords(data, size, getPosition)词汇现在可以按照螺线的形状进行排布了,但是由于没有做碰撞检测,放置点相近得单词重叠在了一起。接下来只需要知道放置词汇时是否会重叠,就可以沿着螺线进行放置尝试,直至所有单词尝试完毕。
碰撞检测算法碰撞检测有多种实现方式,我们采用逐像素比较的方式。使用一个数组来记录整个画布中每个像素点的占用情况,每个单词则在初始化时保存自己的像素占用信息。在放置单词时,将单词的像素占用信息与画布中对应位置的像素信息做对比。在文字放置后,更新画布对应位置的像素占用信息。
为了便于比较和操作,使用一维数组来存储像素信息,在全局初始化一个board数组用于保存整个画布的像素占用情况(长度为画布宽高),每个词汇新建一个sprite数组用于保存自身文字的像素占用情况(长度为文字宽高)。
碰撞检测过程假设变量board存储了整个画布像素信息,每个单词使用sprite存储自身的像素占用信息。