Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Help implementing custom layout #51

Open
diegoaguilar opened this issue Feb 14, 2022 · 1 comment
Open

Help implementing custom layout #51

diegoaguilar opened this issue Feb 14, 2022 · 1 comment

Comments

@diegoaguilar
Copy link

diegoaguilar commented Feb 14, 2022

I've found myself with the following situation:

  • Items placed using pinterest layout are properly arranged. No overlapping, gutters correctly place and distributed
  • Items got an image and text
  • simple layout would just overlap / smash every item
  • I don't particularly need à la pinterest layout but every column starting a a common height

I tried to pass a custom layout overwriting the pinterest layout code.

I've got this:

import { chunk } from "lodash";

export default function(items, props) {
  const { columns, columnWidth, gutterWidth, gutterHeight } = props;

  const columnHeights = [];
  for (let i = 0; i < columns; i++) {
    columnHeights.push(0);
  }

  const positions = items.map(itemProps => {
    const column = columnHeights.indexOf(Math.min.apply(null, columnHeights));

    const height =
      itemProps.itemHeight || (itemProps.itemRect && itemProps.itemRect.height);

    if (!(height && typeof height === "number")) {
      throw new Error(
        'Each child must have an "itemHeight" prop or an "itemRect.height" prop.'
      );
    }

    const x = column * columnWidth + column * gutterWidth;
    const y = columnHeights[column];

    columnHeights[column] += Math.round(height) + gutterHeight;

    return [x, y];
  });

  const allHeights = items.map(itemProps => 
    itemProps.itemHeight || (itemProps.itemRect && itemProps.itemRect.height)
  );

  const chunkHeights = chunk(allHeights, columns);

  const gridWidth = columns * columnWidth + (columns - 1) * gutterWidth;
  const gridHeight = Math.max.apply(null, columnHeights);

  const rows = chunk(positions, columns);
  let previewRowYStart = 0;
  let previewRowYEnd = 0;
  const orderedPositions = rows.map((row: any, rowIndex) => {
    const columnsYPositions = row.map(([x, y]) => y);
    const max = Math.max(...columnsYPositions);
    let yPosition = max;
    if (rowIndex !== 0) {
      const overlap = previewRowYEnd >= max;
      if (overlap) yPosition = (max + (previewRowYEnd - max)) * 1.05;
    }

    previewRowYStart = rowIndex === 0 ? 0 : max;
    previewRowYEnd = max + Math.max(...chunkHeights[rowIndex] as number[]);

    return row.map(([ x ]) => [ x, yPosition ]);
  });

  return { positions: orderedPositions.flat(1), gridWidth, gridHeight };
}

Where basically I'm trying to order the item Y position into chunks according to their row, take the highest and set a common Y for all of them. Also I'd take previous row height and detect the chance of an overlap, adding some extra distance if overlapping.

This seems to work except that in some cases, the distance between rows is huge. I've tried to adjust the yPosition calculation when there's an overlap and also reduced the gutter but I can't get a consistent and logic result.

Any suggestions or directions would be appreciated

@diegoaguilar
Copy link
Author

@dantrain if you could take a look I'd be so pleased

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant