private constraintByContainerSize()

in web/src/app/common/resizable-pane/resizing-calculator.ts [227:323]


  private constraintByContainerSize(
    areaSizeState: ResizableAreaState[],
    containerSize: number,
  ): ResizableAreaState[] {
    areaSizeState = areaSizeState.map((area) => ({
      spec: area.spec,
      currentSize: area.currentSize,
    }));
    const currentSize = this.getEntirePaneSize(areaSizeState);
    if (currentSize === containerSize) return areaSizeState;
    const minSize = this.getMinimumEntireAreaSize(areaSizeState);
    // contents can't be fit in the container even with the minimum size. override container size as the last way.
    if (containerSize < minSize) {
      containerSize = minSize;
      for (const area of areaSizeState) {
        area.currentSize = area.spec.minSizeInPx;
      }
      return areaSizeState;
    }

    if (currentSize < containerSize) {
      // Expanding areas
      let restSizeDiff = containerSize - currentSize;
      let restSumOfExpandRatio = areaSizeState.reduce(
        (a, b) => a + b.spec.resizeRatio,
        0,
      );
      for (const area of areaSizeState) {
        if (area.spec.resizeRatio === 0) continue;
        const expandSize = Math.floor(
          (restSizeDiff / restSumOfExpandRatio) * area.spec.resizeRatio,
        );
        area.currentSize += expandSize;
        restSizeDiff -= expandSize;
        restSumOfExpandRatio -= area.spec.resizeRatio;
      }
      return areaSizeState;
    } else {
      // Shrinking area
      // Shrink operation is not straight because each areas can have different minSizeInPx even they had non-zero resizeRatio
      let restSizeDiff = currentSize - containerSize;
      for (let i = 0; i < 100; i++) {
        // Loops until the specific times to avoid infinity loop if bug occurs
        const shrinkInfo = this.calculateShrinkableAreaInfo(areaSizeState);
        // No shrinkable area anymore, but here should be unreachable.
        if (shrinkInfo.nextShrinkAreaId === '') return areaSizeState;
        if (
          restSizeDiff <
          shrinkInfo.maxShrinkableSizeBeforeReachingMinSizeOfMinShrinkableArea
        ) {
          // Resize can be done without reaching the minSize
          let restSumOfShrinkRatio = shrinkInfo.sumOfShrinkableResizeRatio;
          for (const area of areaSizeState) {
            if (area.spec.resizeRatio === 0) continue;
            if (area.spec.minSizeInPx === area.currentSize) continue;
            const shrinkSize = Math.floor(
              (restSizeDiff / restSumOfShrinkRatio) * area.spec.resizeRatio,
            );
            area.currentSize -= shrinkSize;
            restSizeDiff -= shrinkSize;
            restSumOfShrinkRatio -= area.spec.resizeRatio;
          }
          break;
        } else {
          // Resize can't be done without reaching the minSize of the area
          const nextShrinkAreaReachingLimit = areaSizeState.find(
            (area) => area.spec.id === shrinkInfo.nextShrinkAreaId,
          )!;
          const diff =
            nextShrinkAreaReachingLimit.currentSize -
            nextShrinkAreaReachingLimit.spec.minSizeInPx;
          restSizeDiff -= diff;
          nextShrinkAreaReachingLimit.currentSize =
            nextShrinkAreaReachingLimit.spec.minSizeInPx;
          let restSumOfShrinkRatio =
            shrinkInfo.sumOfShrinkableResizeRatio -
            nextShrinkAreaReachingLimit.spec.resizeRatio;
          let restSizeDiffInThisLoop =
            shrinkInfo.maxShrinkableSizeBeforeReachingMinSizeOfMinShrinkableArea -
            diff;
          for (const area of areaSizeState) {
            if (area.spec.resizeRatio === 0) continue;
            if (area.spec.minSizeInPx === area.currentSize) continue;
            const shrinkSize = Math.floor(
              (restSizeDiffInThisLoop / restSumOfShrinkRatio) *
                area.spec.resizeRatio,
            );
            area.currentSize -= shrinkSize;
            restSizeDiff -= shrinkSize;
            restSizeDiffInThisLoop -= shrinkSize;
            restSumOfShrinkRatio -= area.spec.resizeRatio;
          }
        }
      }
      return areaSizeState;
    }
  }