The Fox is watching you.

基于JS的蒙德里安风格随机色块生成(1) 从准备工作到生成交点

本项目基于JavaScript,随机产生蒙德里安风格的色块。

原本是打算用到主站上的,但是从头搭建所消耗的时间太多了,而且为了节省不必要的时间容易导致审美割裂。因此被当作废案,暂时记录存储。

需求转化

问题的实质是随机直线分割一矩形。蒙德里安风格的色块鲜有十字边界交叉,可以说是交点由一条线遇到另一条线停止而形成,以该点为起点出发,沿已有边界至多有三个方向(初始矩形的四个角只有两个)。

实现思路

  1. 获取屏幕尺寸
  2. 在限定条件下生成随机点,以随机点为基础生成随机线
  3. 判断并且生成交点
  4. 判断并且生成矩形参数
  5. 根据矩形参数绘制矩形

    实现原理

    生成交点部分
    其中我在编写过程中遇到问题最多的就是步骤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']];

添加新评论