【译】三角网格—Triangular mesh
JChehe opened this issue · 0 comments
本文由才华横溢的 maxwellito 撰写。如果你对编写文章感兴趣,可以像他一样提交一份 提案。
这种三角网格效果常出现库和 SVG 中。今天我们将用 canvas 实现它!同时,这也是一个说明坐标系和替换细节而得到漂亮效果的案例。
老规矩,首先是初始化得到一个方形 canvas。
var canvas = document.querySelector('canvas');
var context = canvas.getContext('2d');
var size = window.innerWidth;
canvas.width = size;
canvas.height = size;
创建点网格的常规方式是通过行和列。这些点将会被绘制在 canvas 上,并被存储在一个数组中,以便后续使用。
点是由一个含有 x
、y
属性的对象表示。
行列之间的间距通过 gap
变量表示。我们将点绘制成圆后,便看到网格在 canvas 上的样子。
var line,
lines = [],
gap = size / 7;
for (var y = gap / 2; y <= size; y+= gap) {
line = []
for (var x = gap / 2; x <= size; x+= gap) {
line.push({x: x, y: y})
context.beginPath();
context.arc(x, y, 1, 0, 2 * Math.PI, true);
context.fill();
}
lines.push(line)
}
然后替换隔行的 x 坐标。这里我们通过 odd
变量交替赋值 true 或 false 实现。
一个正三角网格将在新坐标下形成。
var line, dot,
odd = false,
lines = [],
gap = size / 8;
for (var y = gap / 2; y <= size; y+= gap) {
odd = !odd
line = []
for (var x = gap / 4; x <= size; x+= gap) {
dot = {x: x + (odd ? gap/2 : 0), y: y}
line.push(dot)
context.beginPath();
context.arc(dot.x, dot.y, 1, 0, 2 * Math.PI, true);
context.fill();
}
lines.push(line)
}
下一步是使用点绘制三角形。
创建一个接收三角形三个坐标,并连接绘制它们的函数。
function drawTriangle(pointA, pointB, pointC) {
context.beginPath();
context.moveTo(pointA.x, pointA.y);
context.lineTo(pointB.x, pointB.y);
context.lineTo(pointC.x, pointC.y);
context.lineTo(pointA.x, pointA.y);
context.closePath();
context.stroke();
}
现在,结合 drawTriangle
函数和点数组绘制所有三角形。
这部分也许会有点难以理解。脚本会遍历所有线,并组合相邻线的点以形成三角形。为了便于理解,我们将相邻的两条线分别称为 a
和 b
。然后将两线符合要求的点合并到一个数组中,使其看起来像“之”字型:a1
、b1
、a2
、b2
、a3
以此类推。
这将为我们提供了一个含有三角形所有坐标的数组。如:[a1
, b1
, a2
]、[b1
, a2
, b2
], [a2
, b2
, a3
] 等。
var dotLine;
odd = true;
for (var y = 0; y < lines.length - 1; y++) {
odd = !odd
dotLine = []
for (var i = 0; i < lines[y].length; i++) {
dotLine.push(odd ? lines[y][i] : lines[y+1][i])
dotLine.push(odd ? lines[y+1][i] : lines[y][i])
}
for (var i = 0; i < dotLine.length - 2; i++) {
drawTriangle(dotLine[i], dotLine[i+1], dotLine[i+2])
}
}
至此,我们得到一个正三角网格。接着,我们为一个细节赋予魔法。
现在每个点与相邻点之间的间距相同。其实,我们可以将点在该区域内进行位移,而避免与其它点发生重叠(译者注:每个点的安全位移区域是点间距的一半)。利用 Math.random()
对点进行位移。
line.push({
x: x + (Math.random()*.8 - .4) * gap + (odd ? gap/2 : 0),
y: y + (Math.random()*.8 - .4) * gap,
})
另外,还可以增加一些生成艺术的乐趣。比如填充只有 16 种色调的灰色!
var gray = Math.floor(Math.random()*16).toString(16);
context.fillStyle = '#' + gray + gray + gray;
context.fill();
如果想探索该效果的更多实现细节,可看看我的库:triangulr。