本项目基于JavaScript,随机产生蒙德里安风格的色块。
原本是打算用到主站上的,但是从头搭建所消耗的时间太多了,而且为了节省不必要的时间容易导致审美割裂。因此被当作废案,暂时记录存储。
基于JS的蒙德里安风格随机色块生成(2)
基于JS的蒙德里安风格随机色块生成(3)
需求转化
问题的实质是随机直线分割一矩形。蒙德里安风格的色块鲜有十字边界交叉,可以说是交点由一条线遇到另一条线停止而形成,以该点为起点出发,沿已有边界至多有三个方向(初始矩形的四个角只有两个)。
实现思路
- 获取屏幕尺寸
- 在限定条件下生成随机点,以随机点为基础生成随机线
- 判断并且生成交点
- 判断并且生成矩形参数
根据矩形参数绘制矩形
实现原理
见生成交点部分。
其中我在编写过程中遇到问题最多的就是步骤3和步骤4常量初始化
首先需要初始化常量,没什么好说的,主要是一些可调参数。
const AVAILABLE_WIDTH = screen.availWidth; const AVAILABLE_HEIGHT = screen.availHeight; const MIN_LENGTH = AVAILABLE_WIDTH > AVAILABLE_HEIGHT ? AVAILABLE_HEIGHT : AVAILABLE_WIDTH; const RANDOM_LINE_UPPER_BOUND = MIN_LENGTH < 775 ? 16 : 24; const RANDOM_LINE_LOWER_BOUND = MIN_LENGTH < 775 ? 16 : 24; //这两步是为了保证在小屏幕上不会有过多线条,破坏整体美观。默认小屏16条线,大屏24条。 const RANDOM_LINE_COUNT = getRandomInt(RANDOM_LINE_LOWER_BOUND, RANDOM_LINE_UPPER_BOUND); const MIN_DISTANCE = MIN_LENGTH < 520 ? 10 : 30;//保证生成不会过密,色块大小异常 const COLUMN_PROBABILITY = 0.618;//调节纵列线的生成概率 const is_random_direction = false;//选取随机线条方向的生成方式,如果为否则交替生成
通用函数初始化
//随机生成整数 function getRandomInt(MIN, MAX) { return Math.floor(Math.random() * (MAX - MIN)) + MIN; } //二位数组插入三维数组 用于 function insert3DArray(originArr, instertArr, option_1, option_2) { let index = 0; // 找到要插入的位置 while (index < originArr.length && originArr[index][option_1][option_2] < instertArr[option_1][option_2]) { index++; } // 使用splice在找到的位置插入新元素 originArr.splice(index, 0, instertArr); }
随机点线生成
因为最终决定矩形的实际上是随机线,所以优先初始化它。方向是随机或交替的,可以首先初始化好,之后再处理线的基准点。
//数组初始化 var randomLineInfo = []; for (let i = 0; i < RANDOM_LINE_COUNT; i++) { randomLineInfo[i] = []; randomLineInfo[i][0] = []; } //随机纵向横向 if (is_random_direction) { for (let i = 0; i < RANDOM_LINE_COUNT; i++) { if (Math.random() < COLUMN_PROBABILITY) randomLineInfo[i][1] = 'Column'; else randomLineInfo[i][1] = 'Row'; } } else { let is_column = true; if (Math.random() < COLUMN_PROBABILITY) { randomLineInfo[0][1] = 'Column'; is_column = true; } else { randomLineInfo[0][1] = 'Row'; is_column = false; } for (let i = 1; i < RANDOM_LINE_COUNT; i++) { if (is_column) { randomLineInfo[i][1] = 'Row'; is_column = false; } else { randomLineInfo[i][1] = 'Column'; is_column = true; } } } //随机坐标 if (MIN_LENGTH / RANDOM_LINE_COUNT > 1.5 * MIN_DISTANCE) { randomLineInfo[0][0] = [Math.floor(Math.random() * AVAILABLE_WIDTH), Math.floor(Math.random() * AVAILABLE_HEIGHT)]; for (let i = 1; i < RANDOM_LINE_COUNT; i++) { let newCoord = [getRandomInt(0, AVAILABLE_WIDTH), getRandomInt(0, AVAILABLE_HEIGHT)]; let is_too_close = false; for (let j = 0; j < i; j++) { if (Math.abs(newCoord[0] - randomLineInfo[j][0][0]) < MIN_DISTANCE || Math.abs(newCoord[1] - randomLineInfo[j][0][1]) < MIN_DISTANCE) { is_too_close = true; break; } } if (!is_too_close) randomLineInfo[i][0] = newCoord; else i--; } } else { for (let i = 0; i < RANDOM_LINE_COUNT; i++) { randomLineInfo[i][0] = [Math.floor(Math.random() * AVAILABLE_WIDTH), Math.floor(Math.random() * AVAILABLE_HEIGHT)]; } }
生成交点前的一点处理
这一部分还有很大的优化空间。首先做的是建立两个待处理数组,用于临时存储已经处理好的(等待接下来使用)的数组,初始化了屏幕的四条边线。初始化了交点,包括四角。表示方法是Up/Down+Left/Right。
//初始化 待处理列 与 待处理行 let processingRow = [[[0, 0], [AVAILABLE_WIDTH, 0]], [[0, AVAILABLE_HEIGHT], [AVAILABLE_WIDTH, AVAILABLE_HEIGHT]]]; let processingColumn = [[[0, 0], [0, AVAILABLE_HEIGHT]], [[AVAILABLE_WIDTH, 0], [AVAILABLE_WIDTH, AVAILABLE_WIDTH]]]; //初始化 交点 let intersectionInfo = [[0, 0, 'UL'], [AVAILABLE_WIDTH, 0, 'UR'], [0, AVAILABLE_HEIGHT, 'DL'], [AVAILABLE_WIDTH, AVAILABLE_HEIGHT, 'DR']];
评论区(暂无评论)