Skip to content

Commit f27942d

Browse files
committed
[css-layout-api] Add multicol layout example.
1 parent 3a68589 commit f27942d

File tree

1 file changed

+96
-0
lines changed

1 file changed

+96
-0
lines changed

css-layout-api/README.md

Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -310,3 +310,99 @@ function performLayout(constraintSpace, box) {
310310
return new Fragment(fragmentDict);
311311
}
312312
```
313+
314+
### Example layout algorithms
315+
316+
```js
317+
// 'multicol' does a simple multi-column layout.
318+
registerLayout('multicol', class {
319+
*layout(constraintSpace, children, styleMap, opt_breakToken) {
320+
const inlineSize = resolveInlineSize(constraintSpace, styleMap);
321+
322+
// Try and decide the number of size of columns.
323+
const columnCountValue = styleMap.get('column-count');
324+
const columnInlineSizeValue = styleMap.get('column-width');
325+
326+
let columnCount = 1;
327+
let columnInlineSize = inlineSize;
328+
329+
if (columnCountValue) {
330+
columnCount = columnCountValue.value;
331+
}
332+
333+
if (columnInlineSizeValue) {
334+
columnInlineSize = resolveSize(columnInlineSizeValue, inlineSize);
335+
}
336+
337+
if (constraintSpace.inlineScrollOffset &&
338+
columnInlineSize * columnCount > constraintSpace.inlineScrollOffset) {
339+
// NOTE: under this condition, we need to start again to re-resolve lengths?
340+
constraintSpace.willInlineScroll();
341+
return; // Or just continue here?
342+
}
343+
344+
// Create a constraint space which is just the inlineSize of the column.
345+
const colConstraintSpace = new ConstraintSpace({
346+
inlineSize: columnInlineSize
347+
});
348+
349+
// Perform layout on all the children, taking into account the children
350+
// which may fragment in the inline direction.
351+
const childFragments = [];
352+
let childBlockSize = 0;
353+
let layoutOpp;
354+
for (let child of children) {
355+
let breakToken;
356+
do {
357+
const fragment = yield child.doLayout(colConstraintSpace, breakToken);
358+
breakToken = fragment.breakToken;
359+
360+
const gen = colConstraintSpace.layoutOpportunities();
361+
362+
layoutOpp = gen.next().value;
363+
if (layoutOpp.inlineSize < fragment.inlineSize()) {
364+
layoutOpp = gen.next().value;
365+
}
366+
367+
fragment.inlineStart = opp.inlineStart;
368+
fragment.blockStart = opp.blockStart;
369+
colConstraintSpace.addExclusion(fragment, 'inline-flow');
370+
371+
childFragments.push(fragment);
372+
} while (breakToken);
373+
}
374+
375+
// FIXME: This might be wrong.
376+
const childBlockSize =
377+
colConstraintSpace.layoutOpportunities().next().value.blockStart;
378+
379+
// Next, a clever person would nicely balance the columns, we are going
380+
// to do something really simple. :)
381+
const columnBlockSize = Math.ceil(childBlockSize / columnCount);
382+
const columnGap = resolveSize(styleMap.get('column-gap'), inlineSize);
383+
let size = 0;
384+
let columnNum = 0;
385+
let columnEndOffset = 0;
386+
for (let fragment of childFragments) {
387+
if (size && fragment.blockSize + size > columnBlockSize) {
388+
size = 0;
389+
columnNum++;
390+
columnEndOffset += size;
391+
}
392+
393+
fragment.inlineStart += columnNum * (columnGap + columnInlineSize);
394+
fragment.blockStart -= columnEndOffset;
395+
size = Math.max(size, fragment.blockStart + fragment.blockSize);
396+
}
397+
398+
const blockSize =
399+
resolveBlockSize(constraintSpace, styleMap, columnBlockSize);
400+
401+
return {
402+
inlineSize: inlineSize,
403+
blockSize: blockSize,
404+
fragments: childFragments,
405+
};
406+
}
407+
});
408+
```

0 commit comments

Comments
 (0)