mirror of
https://github.com/directus/directus.git
synced 2026-02-06 14:15:04 -05:00
* Map layout and interface improvements: * Disable drag to rotate * Add keyboard shortcut to delete items * Hide unselect button when selection is empty * Add display template setting * Fixed fitData button behaviour * Removed unused hoveredFeatureId * Added translations * Expose clearFilters to the layout.
194 lines
6.0 KiB
TypeScript
194 lines
6.0 KiB
TypeScript
import { Map, Point } from 'maplibre-gl';
|
|
|
|
export class ButtonControl {
|
|
active: boolean;
|
|
element: HTMLElement;
|
|
groupElement?: HTMLElement;
|
|
constructor(private className: string, private callback: (...args: any) => any) {
|
|
this.element = document.createElement('button');
|
|
this.element.className = this.className;
|
|
this.element.onclick = callback;
|
|
this.active = false;
|
|
}
|
|
click(...args: any[]): void {
|
|
this.callback(...args);
|
|
}
|
|
activate(yes: boolean): void {
|
|
this.element.classList[yes ? 'add' : 'remove']('active');
|
|
this.active = yes;
|
|
}
|
|
show(yes: boolean): void {
|
|
this.element.classList[yes ? 'remove' : 'add']('hidden');
|
|
}
|
|
onAdd(): HTMLElement {
|
|
this.groupElement = document.createElement('div');
|
|
this.groupElement.className = 'mapboxgl-ctrl mapboxgl-ctrl-group';
|
|
this.groupElement.appendChild(this.element);
|
|
return this.groupElement;
|
|
}
|
|
onRemove(): void {
|
|
this.element.remove();
|
|
this.groupElement?.remove();
|
|
}
|
|
}
|
|
|
|
type BoxSelectControlOptions = {
|
|
groupElementClass?: string;
|
|
boxElementClass?: string;
|
|
selectButtonClass?: string;
|
|
unselectButtonClass?: string;
|
|
layers: string[];
|
|
};
|
|
|
|
export class BoxSelectControl {
|
|
groupElement: HTMLElement;
|
|
boxElement: HTMLElement;
|
|
|
|
selectButton: ButtonControl;
|
|
unselectButton: ButtonControl;
|
|
|
|
map?: Map & { fire: (event: string, data?: any) => void };
|
|
layers: string[];
|
|
|
|
selecting = false;
|
|
shiftPressed = false;
|
|
startPos: Point | undefined;
|
|
lastPos: Point | undefined;
|
|
|
|
onKeyDownHandler: (event: KeyboardEvent) => any;
|
|
onKeyUpHandler: (event: KeyboardEvent) => any;
|
|
onMouseDownHandler: (event: MouseEvent) => any;
|
|
onMouseMoveHandler: (event: MouseEvent) => any;
|
|
onMouseUpHandler: (event: MouseEvent) => any;
|
|
|
|
constructor(options: BoxSelectControlOptions) {
|
|
this.layers = options?.layers ?? [];
|
|
this.boxElement = document.createElement('div');
|
|
this.boxElement.className = options?.boxElementClass ?? 'selection-box';
|
|
this.groupElement = document.createElement('div');
|
|
this.groupElement.className = options?.groupElementClass ?? 'mapboxgl-ctrl mapboxgl-ctrl-group';
|
|
this.selectButton = new ButtonControl(options?.selectButtonClass ?? 'ctrl-select', () => {
|
|
this.activate(!this.shiftPressed);
|
|
});
|
|
this.unselectButton = new ButtonControl(options?.unselectButtonClass ?? 'ctrl-unselect', () => {
|
|
this.reset();
|
|
this.activate(false);
|
|
this.map!.fire('select.end', { features: [] });
|
|
});
|
|
this.groupElement.appendChild(this.selectButton.element);
|
|
this.groupElement.appendChild(this.unselectButton.element);
|
|
|
|
this.onKeyDownHandler = this.onKeyDown.bind(this);
|
|
this.onKeyUpHandler = this.onKeyUp.bind(this);
|
|
this.onMouseDownHandler = this.onMouseDown.bind(this);
|
|
this.onMouseMoveHandler = this.onMouseMove.bind(this);
|
|
this.onMouseUpHandler = this.onMouseUp.bind(this);
|
|
}
|
|
|
|
onAdd(map: Map): HTMLElement {
|
|
this.map = map as any;
|
|
this.map!.boxZoom.disable();
|
|
this.map!.getContainer().appendChild(this.boxElement);
|
|
this.map!.getContainer().addEventListener('pointerdown', this.onMouseDownHandler, true);
|
|
document.addEventListener('keydown', this.onKeyDownHandler);
|
|
document.addEventListener('keyup', this.onKeyUpHandler);
|
|
return this.groupElement;
|
|
}
|
|
|
|
onRemove(): void {
|
|
this.map!.boxZoom.enable();
|
|
this.boxElement.remove();
|
|
this.groupElement.remove();
|
|
this.map!.getContainer().removeEventListener('pointerdown', this.onMouseDownHandler);
|
|
document.removeEventListener('keydown', this.onKeyDownHandler);
|
|
document.removeEventListener('keyup', this.onKeyUpHandler);
|
|
}
|
|
|
|
active(): boolean {
|
|
return this.shiftPressed || this.selecting;
|
|
}
|
|
|
|
getMousePosition(event: MouseEvent): Point {
|
|
const container = this.map!.getContainer();
|
|
const rect = container.getBoundingClientRect();
|
|
// @ts-ignore
|
|
return new Point(event.clientX - rect.left - container.clientLeft, event.clientY - rect.top - container.clientTop);
|
|
}
|
|
|
|
onKeyDown(event: KeyboardEvent): void {
|
|
if (event.key == 'Shift') {
|
|
this.activate(true);
|
|
}
|
|
if (event.key == 'Escape') {
|
|
this.reset();
|
|
this.activate(false);
|
|
this.map!.fire('select.end', { features: [] });
|
|
}
|
|
}
|
|
|
|
activate(yes: boolean): void {
|
|
this.shiftPressed = yes;
|
|
this.selectButton.activate(yes);
|
|
this.map!.fire(`select.${yes ? 'enable' : 'disable'}`);
|
|
}
|
|
|
|
showUnselect(yes: boolean): void {
|
|
this.unselectButton.show(yes);
|
|
}
|
|
|
|
onKeyUp(event: KeyboardEvent): void {
|
|
if (event.key == 'Shift') {
|
|
this.activate(false);
|
|
}
|
|
}
|
|
|
|
onMouseDown(event: MouseEvent): void {
|
|
if (!this.shiftPressed) {
|
|
return;
|
|
}
|
|
if (event.button === 0) {
|
|
this.selecting = true;
|
|
this.map!.dragPan.disable();
|
|
this.startPos = this.getMousePosition(event);
|
|
this.lastPos = this.startPos;
|
|
document.addEventListener('pointermove', this.onMouseMoveHandler);
|
|
document.addEventListener('pointerup', this.onMouseUpHandler);
|
|
this.map!.fire('select.start');
|
|
}
|
|
}
|
|
|
|
onMouseMove(event: MouseEvent): void {
|
|
this.lastPos = this.getMousePosition(event);
|
|
const minX = Math.min(this.startPos!.x, this.lastPos!.x),
|
|
maxX = Math.max(this.startPos!.x, this.lastPos!.x),
|
|
minY = Math.min(this.startPos!.y, this.lastPos!.y),
|
|
maxY = Math.max(this.startPos!.y, this.lastPos!.y);
|
|
const transform = `translate(${minX}px, ${minY}px)`;
|
|
const width = maxX - minX + 'px';
|
|
const height = maxY - minY + 'px';
|
|
this.updateBoxStyle({ transform, width, height });
|
|
}
|
|
|
|
onMouseUp(event: MouseEvent): void {
|
|
this.reset();
|
|
const features = this.map!.queryRenderedFeatures([this.startPos!, this.lastPos!], {
|
|
layers: this.layers,
|
|
});
|
|
this.map!.fire('select.end', { features, alt: event.altKey });
|
|
}
|
|
|
|
reset(): void {
|
|
this.selecting = false;
|
|
this.updateBoxStyle({ width: '0', height: '0', transform: '' });
|
|
document.removeEventListener('pointermove', this.onMouseMoveHandler);
|
|
document.removeEventListener('pointerup', this.onMouseUpHandler);
|
|
this.map!.dragPan.enable();
|
|
}
|
|
|
|
updateBoxStyle(style: { width: string; height: string; transform: string }): void {
|
|
this.boxElement.style.transform = style.transform;
|
|
this.boxElement.style.width = style.width;
|
|
this.boxElement.style.height = style.height;
|
|
}
|
|
}
|