-
Notifications
You must be signed in to change notification settings - Fork 34
/
spacing.tsx
104 lines (92 loc) · 3.56 KB
/
spacing.tsx
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
/**
* Get the Best Grid Spacing from the given itemWidths.
* The best spacing is the one with a margin that is close to minMargin.
*
* @param {number[]} itemWidths An array of widths. I.e [10, 20, 30]
* @param {number} availableWidth The width of the grid/The amount of space we can work with.
* @param {number} minMargin The minimum margin to keep between items and around the edges.
* @returns {Object} An object containing the best spacing and the item width associated with it.
*/
export function getBestGridItemSpacing(itemWidths, availableWidth, minMargin) {
// Find the best spacing
let bestSpacing = null;
let bestWidth = null;
itemWidths.forEach((width) => {
const spacing = getGridItemSpacing(width, availableWidth, minMargin);
if (!bestSpacing) {
bestSpacing = spacing;
bestWidth = width;
// Best spacing is the one with the smallest margin and smallest extra space
} else if (
spacing.columnCount > 0 &&
(spacing.margin < bestSpacing.margin ||
(spacing.margin === bestSpacing.margin &&
spacing.extra < bestSpacing.extra))
) {
bestSpacing = spacing;
bestWidth = width;
}
});
return {
...bestSpacing,
width: bestWidth,
};
}
/**
* Get the Grid Spacing required for a uniform grid look.
* I.e All the items are spaced evenly apart.
* Take a look at ResultsList.js for an example on how this can be applied.
*
* @param {number} itemWidth The width of the item.
* @param {number} availableWidth The width of the grid/The amount of space we can work with.
* @param {number} minMargin The minimum margin to keep between items and around the edges.
* @param {boolean} [distributeExtraToMargin=true]
* Whether any extra space should be distributed evenly to margin.
* @returns {Object} An object containing the margin, columnCount and extra space remaining.
*/
export function getGridItemSpacing(
itemWidth,
availableWidth,
minMargin,
distributeExtraToMargin = true
) {
// The margin we are working with
let edgeMargin = minMargin;
const innerMargin = edgeMargin * 2;
// The amount of space we can work with
// Not sure if we need to make this a float or not.
const maxContentWidth = availableWidth - edgeMargin * 2;
// The amount of items we can fit in the given space
let columnCount = Math.floor(maxContentWidth / itemWidth);
// We have to check if we can fit in the items
// Or if we have to reduce the columnCount to meet minMargin.
let neededContentWidth = Infinity;
while (columnCount > 0 && neededContentWidth > maxContentWidth) {
neededContentWidth =
columnCount * itemWidth + (columnCount - 1) * innerMargin;
columnCount -= 1;
}
if (neededContentWidth > maxContentWidth) return null;
columnCount += 1;
// Get the extra space we have remaining
let extraSpace =
availableWidth -
(edgeMargin * 2 + // Margin around first and last items
columnCount * itemWidth + // Number of items we can fit in the space
(columnCount - 1) * innerMargin); // Margin between the items
// Try and distribute extra space between the margins
if (distributeExtraToMargin) {
const marginCount = columnCount + 1;
const extraMargin = Math.floor(extraSpace / marginCount);
// Add extra margin and subtract from the extra space
// The reason we divide by 2 is because we want the margin for one side only
// Not the combined margin of both sides
edgeMargin += extraMargin / 2;
extraSpace -= extraMargin * marginCount;
}
return {
margin: edgeMargin,
extra: extraSpace,
columnCount,
};
}