mirror of
https://github.com/streamwall/streamwall.git
synced 2026-01-24 22:22:50 -05:00
Add files missed in code move
This commit is contained in:
80
src/geometry.js
Normal file
80
src/geometry.js
Normal file
@@ -0,0 +1,80 @@
|
||||
import isEqual from 'lodash/isEqual'
|
||||
|
||||
export function boxesFromViewContentMap(width, height, viewContentMap) {
|
||||
const boxes = []
|
||||
const visited = new Set()
|
||||
|
||||
function isPosContent(x, y, content) {
|
||||
const checkIdx = width * y + x
|
||||
return (
|
||||
!visited.has(checkIdx) && isEqual(viewContentMap.get(checkIdx), content)
|
||||
)
|
||||
}
|
||||
|
||||
function findLargestBox(x, y) {
|
||||
const idx = width * y + x
|
||||
const spaces = [idx]
|
||||
const content = viewContentMap.get(idx)
|
||||
|
||||
let maxY
|
||||
for (maxY = y + 1; maxY < height; maxY++) {
|
||||
if (!isPosContent(x, maxY, content)) {
|
||||
break
|
||||
}
|
||||
spaces.push(width * maxY + x)
|
||||
}
|
||||
|
||||
let cx = x
|
||||
let cy = y
|
||||
scan: for (cx = x + 1; cx < width; cx++) {
|
||||
for (cy = y; cy < maxY; cy++) {
|
||||
if (!isPosContent(cx, cy, content)) {
|
||||
break scan
|
||||
}
|
||||
}
|
||||
for (let cy = y; cy < maxY; cy++) {
|
||||
spaces.push(width * cy + cx)
|
||||
}
|
||||
}
|
||||
const w = cx - x
|
||||
const h = maxY - y
|
||||
spaces.sort()
|
||||
return { content, x, y, w, h, spaces }
|
||||
}
|
||||
|
||||
for (let y = 0; y < width; y++) {
|
||||
for (let x = 0; x < height; x++) {
|
||||
const idx = width * y + x
|
||||
if (visited.has(idx) || viewContentMap.get(idx) === undefined) {
|
||||
continue
|
||||
}
|
||||
|
||||
const box = findLargestBox(x, y)
|
||||
boxes.push(box)
|
||||
for (const boxIdx of box.spaces) {
|
||||
visited.add(boxIdx)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return boxes
|
||||
}
|
||||
|
||||
export function idxToCoords(gridCount, idx) {
|
||||
const x = idx % gridCount
|
||||
const y = Math.floor(idx / gridCount)
|
||||
return { x, y }
|
||||
}
|
||||
|
||||
export function idxInBox(gridCount, start, end, idx) {
|
||||
let { x: startX, y: startY } = idxToCoords(gridCount, start)
|
||||
let { x: endX, y: endY } = idxToCoords(gridCount, end)
|
||||
const { x, y } = idxToCoords(gridCount, idx)
|
||||
const lowX = Math.min(startX, endX)
|
||||
const highX = Math.max(startX, endX)
|
||||
const lowY = Math.min(startY, endY)
|
||||
const highY = Math.max(startY, endY)
|
||||
const xInBox = x >= lowX && x <= highX
|
||||
const yInBox = y >= lowY && y <= highY
|
||||
return xInBox && yInBox
|
||||
}
|
||||
91
src/geometry.test.js
Normal file
91
src/geometry.test.js
Normal file
@@ -0,0 +1,91 @@
|
||||
import { boxesFromViewContentMap } from './geometry'
|
||||
|
||||
function example([text]) {
|
||||
return text
|
||||
.replace(/\s/g, '')
|
||||
.split('')
|
||||
.map((c) => (c === '.' ? undefined : { url: c }))
|
||||
}
|
||||
|
||||
const box1 = example`
|
||||
ab
|
||||
ab
|
||||
`
|
||||
|
||||
const box2 = example`
|
||||
aa
|
||||
bb
|
||||
`
|
||||
|
||||
const box3 = example`
|
||||
aac
|
||||
aaa
|
||||
dae
|
||||
`
|
||||
|
||||
const box4 = example`
|
||||
...
|
||||
.aa
|
||||
.aa
|
||||
`
|
||||
|
||||
const box5 = example`
|
||||
..a
|
||||
..a
|
||||
.aa
|
||||
`
|
||||
|
||||
describe.each([
|
||||
[
|
||||
2,
|
||||
2,
|
||||
box1,
|
||||
[
|
||||
{ content: { url: 'a' }, x: 0, y: 0, w: 1, h: 2, spaces: [0, 2] },
|
||||
{ content: { url: 'b' }, x: 1, y: 0, w: 1, h: 2, spaces: [1, 3] },
|
||||
],
|
||||
],
|
||||
[
|
||||
2,
|
||||
2,
|
||||
box2,
|
||||
[
|
||||
{ content: { url: 'a' }, x: 0, y: 0, w: 2, h: 1, spaces: [0, 1] },
|
||||
{ content: { url: 'b' }, x: 0, y: 1, w: 2, h: 1, spaces: [2, 3] },
|
||||
],
|
||||
],
|
||||
[
|
||||
3,
|
||||
3,
|
||||
box3,
|
||||
[
|
||||
{ content: { url: 'a' }, x: 0, y: 0, w: 2, h: 2, spaces: [0, 1, 3, 4] },
|
||||
{ content: { url: 'c' }, x: 2, y: 0, w: 1, h: 1, spaces: [2] },
|
||||
{ content: { url: 'a' }, x: 2, y: 1, w: 1, h: 1, spaces: [5] },
|
||||
{ content: { url: 'd' }, x: 0, y: 2, w: 1, h: 1, spaces: [6] },
|
||||
{ content: { url: 'a' }, x: 1, y: 2, w: 1, h: 1, spaces: [7] },
|
||||
{ content: { url: 'e' }, x: 2, y: 2, w: 1, h: 1, spaces: [8] },
|
||||
],
|
||||
],
|
||||
[
|
||||
3,
|
||||
3,
|
||||
box4,
|
||||
[{ content: { url: 'a' }, x: 1, y: 1, w: 2, h: 2, spaces: [4, 5, 7, 8] }],
|
||||
],
|
||||
[
|
||||
3,
|
||||
3,
|
||||
box5,
|
||||
[
|
||||
{ content: { url: 'a' }, x: 2, y: 0, w: 1, h: 3, spaces: [2, 5, 8] },
|
||||
{ content: { url: 'a' }, x: 1, y: 2, w: 1, h: 1, spaces: [7] },
|
||||
],
|
||||
],
|
||||
])('boxesFromViewContentMap(%i, %i, %j)', (width, height, data, expected) => {
|
||||
test(`returns expected ${expected.length} boxes`, () => {
|
||||
const stateURLMap = new Map(data.map((v, idx) => [idx, v]))
|
||||
const result = boxesFromViewContentMap(width, height, stateURLMap)
|
||||
expect(result).toStrictEqual(expected)
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user