@antv/g2
Version:
the Grammar of Graphics in Javascript
86 lines (81 loc) • 2.63 kB
text/typescript
import { get, each } from '@antv/util';
import { BBox, IGroup, IShape } from '../../../dependents';
import { intersect } from '../../../util/collision-detect';
import { LabelItem } from '../interface';
import { getLabelBackgroundInfo } from '../util';
import { createWorker } from '../util/createWorker';
import { code as layoutCode } from './worker/hide-overlap';
type Item = {
x: number;
y: number;
width: number;
height: number;
rotation?: number;
visible?: boolean;
};
const layout = (items: Item[]): Item[] => {
const boxes = items.slice();
for (let i = 0; i < boxes.length; i++) {
const box1 = boxes[i];
if (box1.visible) {
for (let j = i + 1; j < boxes.length; j++) {
const box2 = boxes[j];
if (box1 !== box2 && box2.visible) {
if (intersect(box1, box2)) {
box2.visible = false;
}
}
}
}
}
return boxes;
}
const cache: Map<string, any> = new Map();
const worker = createWorker(layoutCode);
/**
* label 防遮挡布局:在不改变 label 位置的情况下对相互重叠的 label 进行隐藏(非移除)
* 不同于 'overlap' 类型的布局,该布局不会对 label 的位置进行偏移调整。
* @param labels 参与布局调整的 label 数组集合
*/
export function hideOverlap(labelItems: LabelItem[], labels: IGroup[], shapes: IShape[] | IGroup[], region: BBox) {
// todo 添加 label rank
return new Promise((resolve) => {
const boxes = labels.map((d, idx) => ({
...getLabelBackgroundInfo(d, labelItems[idx], get(labelItems[idx], 'background.padding')),
visible: true,
}));
const memoKey = JSON.stringify(boxes);
const cb = (items: Item[]) => {
cache.set(memoKey, items);
each(items, ({ visible }, idx) => {
const labelShape = labels[idx];
if (visible) {
labelShape?.show()
} else {
labelShape?.hide();
}
});
return resolve(items);
}
if (cache.get(memoKey)) {
cb(cache.get(memoKey))
} else if (worker) {
// Do layout in worker.
try {
worker.postMessage(JSON.stringify({ type: 'hide-overlap', items: boxes }));
worker.onmessage = (e) => cb(Array.isArray(e.data) ? e.data : []);
worker.onmessageerror = (e) => {
console.warn('[AntV G2] Web worker is not available');
// Normal layout in main thread.
cb(layout(boxes));
};
} catch (e) {
console.error(e);
cb(layout(boxes));
}
} else {
// Normal layout in main thread.
cb(layout(boxes));
}
});
}