blog icon indicating copy to clipboard operation
blog copied to clipboard

【译】欢乐分队—Joy Division

Open JChehe opened this issue 5 years ago • 0 comments

原文:Joy Division

欢乐分队的专辑封面有一段非常有趣的历史。同时也是一个数据驱动艺术的惊艳案例。

Unknown Pleasures 欢乐分队的《Unknown Pleasures》专辑封面

这里我们打算使用 canvas 实现,没有额外 API。只需在 HTML 中放置一个 300x300 像素的 元素。

首先进行初始化,没有任何渲染操作。

var canvas = document.querySelector('canvas');
var context = canvas.getContext('2d');

var size = window.innerWidth;

canvas.width = size;
canvas.height = size;

这为我们提供了在页面上绘制的 context 上下文。

首先,在 canvas 上绘制由一系列点组成的线段。然后,将每个点替换成随机数,以达到期待的效果。

定义一些基本变量:

  • step:指定相邻点之间的距离,以像素为单位。
  • lines:存放线段的数组。
var step = 10;
var lines = [];

下面编写函数来生成线。线由一系列点(拥有 x、y 属性的对象)组成。

// Create the lines
for( var i = step; i <= size - step; i += step) {
    
  var line = [];
  for( var j = step; j <= size - step; j+= step ) {
    var point = {x: j, y: i};
    line.push(point)
  } 
  lines.push(line);
}

下一步是绘制线段。和 上篇教程 一样,我们先绘制简单的东西,然后再进行扩展。

// Do the drawing
for(var i = 0; i < lines.length; i++) {

  context.beginPath();
  context.moveTo(lines[i][0].x, lines[i][0].y)
  
  for( var j = 0; j < lines[i].length; j++) {
    context.lineTo(lines[i][j].x, lines[i][j].y);
  }

  context.stroke();
}

多条线段

现在,canvas 上就拥有多条线段。下一步是替换线段里的点。该操作将在第一层循环(创建点的时候)里执行。

var random = Math.random() * 10;
var point = {x: j, y: i + random};

每个点都发生了跳动

噢,现在线的每个点都发生了跳动。但我们期望这些变化集中在线的中间区域,即越靠近线中心的点变化幅度越大,两侧越小。下面通过一个独立函数实现。

var distanceToCenter = Math.abs(j - size / 2);
var variance = Math.max(size / 2 - 50 - distanceToCenter, 0);
var random = Math.random() * variance / 2 * -1;

交叉重叠

现在看起来有点混乱,每条线都存在交叉重叠。这里使用 fill 方法进行覆盖。

首先,设置填充的样式。

context.fillStyle = '#f9f9f9';
context.lineWidth = 2;

设置 fill 样式

然后在每条线绘制后执行 fill 方法,这将会覆盖每个图层下面混乱的线。

译者注:当路径是非封闭图形时,canvas 会直接连接始点和终点,从而形成封闭图形。

context.fill()

fill

快要完成了,唯一剩下的事情是让线看起来更圆滑。二次贝塞尔曲线可以做到这点,只需在两点之间创建一个控制点即可。quadraticCurveTo 就是最后一步。

for( var j = 0; j < lines[i].length - 2; j++) {
    var xc = (lines[i][j].x + lines[i][j + 1].x) / 2;
    var yc = (lines[i][j].y + lines[i][j + 1].y) / 2;
    context.quadraticCurveTo(lines[i][j].x, lines[i][j].y, xc, yc);
  }

  context.quadraticCurveTo(lines[i][j].x, lines[i][j].y, lines[i][j + 1].x, lines[i][j + 1].y);

最终作品——欢乐分队

我们最终得到它了!你可以对每个步骤进行调整,或者更改样式和颜色,从而得到不同效果。一切都令人兴奋!

JChehe avatar Aug 10 '18 15:08 JChehe