Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

【译】皮特·蒙德里安—Piet Mondrian #31

Open
JChehe opened this issue Sep 5, 2018 · 0 comments
Open

【译】皮特·蒙德里安—Piet Mondrian #31

JChehe opened this issue Sep 5, 2018 · 0 comments

Comments

@JChehe
Copy link
Owner

JChehe commented Sep 5, 2018

原文:Piet Mondrian

用代码复现皮特·蒙德里安的艺术作品并不是件简单的事情。老实说,我认为没有方法能复现他的作品,毕竟它们都是手绘的。但我们可以尝试复现皮特作品的部分工作,这也是本教程要阐述的部分。当然,我们也会进行上色。

老规矩,以下是初始化代码,其中包括设置 canvas 大小和使用 window.devicePixelRatio 缩放 canvas 以适配视网膜屏幕。而页面中仅有一个 <canvas> 元素。

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

var size = window.innerWidth;
var dpr = window.devicePixelRatio;
canvas.width = size * dpr;
canvas.height = size * dpr;
context.scale(dpr, dpr);
context.lineWidth = 8;

我采取的方法并不是完美的。首先创建一个大方块(canvas),然后将它进行分割。我会选择一条线(水平或竖直)将其分为多个方块,后续会为分割操作添加随机因子,而不是将所有方块都进行分割,这样应该能呈现出蒙德里安的风格,尽管会有数学上死板的感觉。

创建一组方块。

var squares = [{
  x: 0,
  y: 0,
  width: size,
  height: size
}];

一如既往地创建 “draw” 函数并进行调用。这样就能我们所做的东西。

function draw() {
  for (var i = 0; i < squares.length; i++) {
    context.beginPath();
    context.rect(
      squares[i].x,
      squares[i].y,
      squares[i].width,
      squares[i].height
    );
    context.stroke();
  }
}

draw()

01

这会遍历所有方块(目前仅有一个方块,并绘制在 canvas 上)。

现在,创建一个用于寻找在哪个方块进行分割的函数,该函数会在我们指定的方向上对方块进行分割。

function splitSquaresWith(coordinates) {
  // 遍历找出需要进行分割的方块
}

function splitOnX(square, splitAt) {
  // 基于提供的 x 坐标,创建两个新方块
}

function splitOnY(square, splitAt) {
  // 基于提供的 y 坐标,创建两个方块
}

splitSquaresWith({x: 160})
splitSquaresWith({y: 160})

代码末尾调用了分割方块的函数,分别在 x、y 的中间位置。若代码能正常运行,我们就可以做更多的分裂操作。但就目前而言,更适合试验。

splitSquaresWith 函数:

const { x, y } = coordinates;

for (var i = squares.length - 1; i >= 0; i--) {
  const square = squares[i];
  
  if (x && x > square.x && x < square.x + square.width) {
    squares.splice(i, 1);
    splitOnX(square, x);
  }

  if (y && y > square.y && y < square.y + square.height) {
    squares.splice(i, 1);
    splitOnY(square, y);
  }
}

这里使用了一些小技巧:

  • const { x, y } = coordinates 会提取对象的 xy 变量,如 {x: 160}{y: 160}
  • 使用 (var i = squares.length - 1; i >= 0; i--) 逆序遍历方块,是为了让新元素剔除出循环(分割操作会将一个方块替换为两个)。逆序遍历意味着在遍历下标无需调整的同时,避免新方块不会被再次分割。

当然,现在还是仅有一个方块,这是因为 splitOn 函数还未实现。实质上两者(splitOnXsplitOnY)非常相似。

splitOnX

var squareA = {
  x: square.x,
  y: square.y,
  width: square.width - (square.width - splitAt + square.x),
  height: square.height
};

var squareB = {
  x: splitAt,
  y: square.y,
  width: square.width - splitAt + square.x,
  height: square.height
};

squares.push(squareA);
squares.push(squareB);

splitOnY

var squareA = {
  x: square.x,
  y: square.y,
  width: square.width,
  height: square.height - (square.height - splitAt + square.y)
};

var squareB = {
  x: square.x,
  y: splitAt,
  width: square.width,
  height: square.height - splitAt + square.y
};

squares.push(squareA);
squares.push(squareB);

02

这两个函数均将先前的一个方块分割成两个方块,并将创建的方块添加到 squares 数组中。通过两次居中分割,最终形成了一个窗口。

取消两次硬编码的分割调用,通过 step 变量,遍历多次进行分割。

var step = size / 6;

然后循环遍历。

for (var i = 0; i < size; i += step) {
  splitSquaresWith({ y: i });
  splitSquaresWith({ x: i });
}

03

这就有了多个方块。通过添加随机因子,将原来每次 100% 分割变为 50% 的机会进行分割。

if(Math.random() > 0.5) {
  squares.splice(i, 1);
  splitOnX(square, x); 
}

04

哇喔,看起来不错。y 轴同理。

if(Math.random() > 0.5) {
  squares.splice(i, 1);
  splitOnY(square, y); 
}

05

这就是我们想要的形状和结构!与往常一样,所有教程均可点击编辑器与案例之间的小箭头,让代码重新运行(译者注:原文可体验)。每次点击均可看到不同形状的蒙德里安结构。

现在,让我们为它赋予色彩。首先,定义变量。使用漂亮的红蓝黄色。

var white = '#F2F5F1';
var colors = ['#D40920', '#1356A2', '#F7D842']

我们随机选择三个方块,为它们各自赋予一种颜色。你可能会看到仅有 1 或 2 种颜色,这是因为同一个方块被随机选中了两次以上。

for (var i = 0; i < colors.length; i++) {
  squares[Math.floor(Math.random() * squares.length)].color = colors[i];
}

当然,还需要确保在 draw 函数内进行填充操作。

if(squares[i].color) {
  context.fillStyle = squares[i].color;
} else {
  context.fillStyle = white
}
context.fill()

06

美丽的色彩!

基于网格,你可以轻松增加或减少复杂性。

var step = size / 20;

07

var step = size / 4;

08

var step = size / 7;

09

这就是我们拥有的蒙德里安作品。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant