useCalcGridLayout.ts
4.48 KB
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
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
import { unref } from 'vue';
import { Layout } from 'vue3-grid-layout';
import { DEFAULT_WIDGET_HEIGHT, DEFAULT_WIDGET_WIDTH, DEFAULT_MAX_COL } from '../config/config';
interface GapRecord {
maxGap: number;
startIndex: Nullable<number>;
endIndex: Nullable<number>;
}
/**
* @description calculate where to place the component
* @returns
*/
export function useCalcGridLayout() {
const calcLayoutInfo = (
layoutInfo: Layout[],
randomLayout = { width: DEFAULT_WIDGET_WIDTH, height: DEFAULT_WIDGET_HEIGHT }
) => {
let maxWidth = 0;
let maxHeight = 0;
let maxWidthRecord = {} as unknown as Layout;
let maxHeightRecord = {} as unknown as Layout;
for (const item of unref(layoutInfo)) {
const { x, y, h, w } = item;
if (x + w > maxWidth) {
maxWidth = x + w;
maxWidthRecord = item;
}
if (y + h > maxHeight) {
maxHeight = y + h;
maxHeightRecord = item;
}
}
maxWidth = maxWidthRecord.x + maxWidthRecord.w;
maxHeight = maxHeightRecord.y + maxHeightRecord.h;
const array = Array.from({ length: maxHeight }, (_value) => {
return Array.from({ length: maxWidth });
});
for (const item of layoutInfo) {
const { x, y, w, h } = item;
for (let i = 0; i < h; i++) {
const rowIndex = y + i > array.length - 1 ? array.length - 1 : y + i;
const colEnd = x + w;
const row = array[rowIndex];
row.fill(true, x, colEnd);
}
}
const checkAreaIsAvaliable = (rowIndex: number, rowRecord: GapRecord[]) => {
const { height } = randomLayout;
for (const { startIndex: colStartIndex } of rowRecord) {
let record: GapRecord = { maxGap: 0, startIndex: null, endIndex: null };
const heightGapRecord: GapRecord[] = [];
for (let i = 0; i < height; i++) {
const rowStartIndex = rowIndex + i > array.length - 1 ? array.length - 1 : rowIndex + i;
const row = array[rowStartIndex];
const col = row[colStartIndex!];
if (col) {
if (record.maxGap > 0) heightGapRecord.push(record);
record = { maxGap: 0, startIndex: null, endIndex: null };
}
if (!col) {
record = {
maxGap: record.maxGap + 1,
startIndex: record.startIndex === null ? rowStartIndex : record.startIndex,
endIndex: rowStartIndex,
};
}
if (i + 1 === height) if (record.maxGap > 0) heightGapRecord.push(record);
}
const minHeight = heightGapRecord.length
? Math.min(...heightGapRecord.map((item) => item.maxGap))
: 0;
if (minHeight >= height) {
let flag = true;
for (let colIndex = colStartIndex!; colIndex < record.endIndex!; colIndex++) {
for (let _rowIndex = rowIndex; _rowIndex < height; _rowIndex++) {
if (array[_rowIndex][colIndex]) {
flag = false;
break;
}
}
}
if (flag) return { y: rowIndex, x: colStartIndex!, flag: true };
}
}
return { flag: false, x: 0, y: 0 };
};
for (let rowIndex = 0; rowIndex < array.length; rowIndex++) {
const row = array[rowIndex];
let record: GapRecord = { maxGap: 0, startIndex: null, endIndex: null };
const widthGapRecord: GapRecord[] = [];
const { width } = unref(randomLayout);
for (let colIndex = 0; colIndex < DEFAULT_MAX_COL; colIndex++) {
const col = row[colIndex];
if (col) {
if (record.maxGap > 0) widthGapRecord.push(record);
record = { maxGap: 0, startIndex: null, endIndex: null };
}
if (!col) {
record = {
maxGap: record.maxGap + 1,
startIndex: record.startIndex === null ? colIndex : record.startIndex,
endIndex: colIndex,
};
}
if (colIndex + 1 === DEFAULT_MAX_COL) if (record.maxGap > 0) widthGapRecord.push(record);
}
const maxWidth = widthGapRecord.length
? Math.max(...widthGapRecord.map((item) => item.maxGap))
: 0;
if (maxWidth >= width) {
const maxRecordList = widthGapRecord.filter((item) => item.maxGap >= maxWidth);
const { flag, x, y } = checkAreaIsAvaliable(rowIndex, maxRecordList);
if (flag) return { x, y, w: randomLayout.width, h: randomLayout.height };
}
}
return { x: 0, y: array.length, w: randomLayout.width, h: randomLayout.height };
};
return { calcLayoutInfo };
}