function findAvailablePlaces()

in client/src/components/special/grid-layout/layout.js [211:374]


  function findAvailablePlaces (oldLayout, key, box) {
    if (oldLayout.filter(item => item.i === key).length > 0) {
      return;
    }
    const createZone = ({x, y, w, h}) => {
      return {
        x,
        y,
        x2: x + w,
        y2: y + h,
        w,
        h,
        size: w * h
      };
    };
    const xSorter = (zoneA, zoneB) => {
      if (zoneA.x < zoneB.x) {
        return -1;
      } else if (zoneA.x > zoneB.x) {
        return 1;
      }
      return 0;
    };
    const ySorter = (zoneA, zoneB) => {
      if (zoneA.y < zoneB.y) {
        return -1;
      } else if (zoneA.y > zoneB.y) {
        return 1;
      }
      return 0;
    };
    const sizeSorter = (zoneA, zoneB) => {
      if (zoneA.size < zoneB.size) {
        return -1;
      } else if (zoneA.size > zoneB.size) {
        return 1;
      }
      return 0;
    };
    const breakpointsX = [];
    if (box.w < Infinity) {
      for (let i = 0; i <= box.w; i++) {
        breakpointsX.push(i);
      }
    } else {
      breakpointsX.push(0);
      breakpointsX.push(box.w);
    }
    const breakpointsY = [0, box.h];
    for (let i = 0; i < oldLayout.length; i++) {
      const layoutItem = oldLayout[i];
      if (breakpointsX.indexOf(layoutItem.x) === -1) {
        breakpointsX.push(layoutItem.x);
      }
      if (breakpointsX.indexOf(layoutItem.x + layoutItem.w) === -1) {
        breakpointsX.push(layoutItem.x + layoutItem.w);
      }
      if (breakpointsY.indexOf(layoutItem.y) === -1) {
        breakpointsY.push(layoutItem.y);
      }
      if (breakpointsY.indexOf(layoutItem.y + layoutItem.h) === -1) {
        breakpointsY.push(layoutItem.y + layoutItem.h);
      }
    }
    breakpointsX.sort((a, b) => a - b);
    breakpointsY.sort((a, b) => a - b);
    let zones = [];
    const layoutItemOverZone = (layoutItem, zone) => {
      return layoutItem.x <= zone.x && layoutItem.x + layoutItem.w >= zone.x &&
        layoutItem.x <= zone.x + zone.w && layoutItem.x + layoutItem.w >= zone.x + zone.w &&
        layoutItem.y <= zone.y && layoutItem.y + layoutItem.h >= zone.y &&
        layoutItem.y <= zone.y + zone.h && layoutItem.y + layoutItem.h >= zone.y + zone.h;
    };
    for (let i = 0; i < breakpointsX.length - 1; i++) {
      for (let j = 0; j < breakpointsY.length - 1; j++) {
        const zone = createZone({
          x: breakpointsX[i],
          y: breakpointsY[j],
          w: breakpointsX[i + 1] - breakpointsX[i],
          h: breakpointsY[j + 1] - breakpointsY[j]
        });
        zone.empty = true;
        for (let z = 0; z < oldLayout.length; z++) {
          if (layoutItemOverZone(oldLayout[z], zone)) {
            zone.empty = false;
            break;
          }
        }
        if (zone.empty) {
          zones.push(zone);
        }
      }
    }
    const buildEmptyZonesOfSize = (size, originalZones) => {
      const result = [];
      const findZoneWithWidthAt = (x, y, w) => {
        for (let j = 0; j < originalZones.length; j++) {
          if (originalZones[j].x === x && originalZones[j].y === y && originalZones[j].w === w) {
            return originalZones[j];
          }
        }
        return null;
      };
      const firstStepZones = [];
      for (let i = 0; i < originalZones.length; i++) {
        const startZone = originalZones[i];
        let nextZone = startZone;
        while (nextZone.y2 - startZone.y < size.h) {
          let next = findZoneWithWidthAt(nextZone.x, nextZone.y2, nextZone.w);
          if (next) {
            nextZone = next;
          } else {
            break;
          }
        }
        if (nextZone.y2 - startZone.y >= size.h) {
          firstStepZones.push(createZone({
            x: startZone.x,
            y: startZone.y,
            w: startZone.w,
            h: nextZone.y2 - startZone.y
          }));
        }
      }
      const findZoneWithHeightAt = (x, y, h) => {
        for (let j = 0; j < firstStepZones.length; j++) {
          if (firstStepZones[j].x === x && firstStepZones[j].y === y && firstStepZones[j].h === h) {
            return firstStepZones[j];
          }
        }
        return null;
      };
      for (let i = 0; i < firstStepZones.length; i++) {
        const startZone = firstStepZones[i];
        let nextZone = startZone;
        while (nextZone.x2 - startZone.x < size.w) {
          let next = findZoneWithHeightAt(nextZone.x2, nextZone.y, nextZone.h);
          if (next) {
            nextZone = next;
          } else {
            break;
          }
        }
        if (nextZone.x2 - startZone.x >= size.w) {
          result.push(createZone({
            x: startZone.x,
            y: startZone.y,
            w: nextZone.x2 - startZone.x,
            h: startZone.h
          }));
        }
      }
      return result;
    };
    const size = defaultSizes[key] || {w: 1, h: 1};
    const availableZones = buildEmptyZonesOfSize(size, zones);
    availableZones.sort((zoneA, zoneB) => {
      return ySorter(zoneA, zoneB) || xSorter(zoneA, zoneB) || sizeSorter(zoneA, zoneB);
    });
    return availableZones.filter((zone, index, array) => {
      const [originalZone] = array.filter(z => z.x === zone.x && z.y === zone.y);
      return array.indexOf(originalZone) === index;
    });
  }