From 8e47d083e81af59e02efb21b8c145e71c496a9ee Mon Sep 17 00:00:00 2001
From: wizardforcel <562826179@qq.com>
Date: Sun, 13 May 2018 16:52:35 +0800
Subject: [PATCH] 19.
---
19.md | 225 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 224 insertions(+), 1 deletion(-)
diff --git a/19.md b/19.md
index 70f1095..8a99aae 100644
--- a/19.md
+++ b/19.md
@@ -276,7 +276,7 @@ class ToolSelect {
我们还需要能够改变颜色 - 所以让我们添加一个控件。 `type`属性为颜色的 HTML ``元素为我们提供了专门用于选择颜色的表单字段。 这种字段的值始终是`"#RRGGBB"`格式(红色,绿色和蓝色分量,每种颜色两位数字)的 CSS 颜色代码。 当用户与它交互时,浏览器将显示一个颜色选择器界面。
-该控件创建这样一个字段,并将其连接起来,与应用程序状态的`color`属性保持同步。
+该控件创建这样一个字段,并将其连接起来,与应用状态的`color`属性保持同步。
```js
class ColorSelect {
@@ -332,3 +332,226 @@ function rectangle(start, state, dispatch) {
return drawRectangle;
}
```
+
+此实现中的一个重要细节是,拖动时,矩形将从原始状态重新绘制在图片上。 这样,您可以在创建矩形时将矩形再次放大和缩小,中间的矩形不会在最终图片中残留。 这是不可变图片对象实用的原因之一 - 稍后我们会看到另一个原因。
+
+实现洪水填充涉及更多东西。 这是一个工具,填充和指针下的像素,和颜色相同的所有相邻像素。 “相邻”是指水平或垂直直接相邻,而不是对角线。 此图片表明,在标记像素处使用填充工具时,着色的一组像素:
+
+![]()
+
+有趣的是,我们的实现方式看起来有点像第 7 章中的寻路代码。那个代码搜索图来查找路线,但这个代码搜索网格来查找所有“连通”的像素。 跟踪一组可能的路线的问题是类似的。
+
+```js
+const around = [{dx: -1, dy: 0}, {dx: 1, dy: 0},
+ {dx: 0, dy: -1}, {dx: 0, dy: 1}];
+
+function fill({x, y}, state, dispatch) {
+ let targetColor = state.picture.pixel(x, y);
+ let drawn = [{x, y, color: state.color}];
+ for (let done = 0; done < drawn.length; done++) {
+ for (let {dx, dy} of around) {
+ let x = drawn[done].x + dx, y = drawn[done].y + dy;
+ if (x >= 0 && x < state.picture.width &&
+ y >= 0 && y < state.picture.height &&
+ state.picture.pixel(x, y) == targetColor &&
+ !drawn.some(p => p.x == x && p.y == y)) {
+ drawn.push({x, y, color: state.color});
+ }
+ }
+ }
+ dispatch({picture: state.picture.draw(drawn)});
+}
+```
+
+绘制完成的像素的数组可以兼作函数的工作列表。 对于每个到达的像素,我们必须看看任何相邻的像素是否颜色相同,并且尚未覆盖。 随着新像素的添加,循环计数器落后于绘制完成的数组的长度。 任何前面的像素仍然需要探索。 当它赶上长度时,没有剩下未探测的像素,并且该函数就完成了。
+
+最终的工具是一个颜色选择器,它允许您指定图片中的颜色,来将其用作当前的绘图颜色。
+
+```js
+function pick(pos, state, dispatch) {
+ dispatch({color: state.picture.pixel(pos.x, pos.y)});
+}
+```
+
+我们现在可以测试我们的应用了!
+
+```html
+
+
+```
+
+## 保存和加载
+
+当我们画出我们的杰作时,我们会想要保存它以备后用。 我们应该添加一个按钮,用于将当前图片下载为图片文件。 这个控件提供了这个按钮:
+
+```js
+class SaveButton {
+ constructor(state) {
+ this.picture = state.picture;
+ this.dom = elt("button", {
+ onclick: () => this.save()
+ }, "\u{1f4be} Save");
+ }
+ save() {
+ let canvas = elt("canvas");
+ drawPicture(this.picture, canvas, 1);
+ let link = elt("a", {
+ href: canvas.toDataURL(),
+ download: "pixelart.png"
+ });
+ document.body.appendChild(link);
+ link.click();
+ link.remove();
+ }
+ setState(state) { this.picture = state.picture; }
+}
+```
+
+组件会跟踪当前图片,以便在保存时可以访问它。 为了创建图像文件,它使用`