Skip to content
Snippets Groups Projects
Commit 6481d53a authored by rhenck's avatar rhenck
Browse files

[editor] Improve dynamic positioning

- Add (editable) rows to the grid
- Add drag and drop functionality to grid elements. The element is in 
'absolute' positioning mode while being dragged and snaps back to the 
grid when droppped.
parent cb8b0e69
No related branches found
No related tags found
No related merge requests found
......@@ -21,6 +21,7 @@ export interface UnitPageSection {
backgroundColor: string;
dynamicPositioning: boolean;
gridColumnSizes: string;
gridRowSizes: string;
}
export interface UnitUIElement {
......
import { Component, Input, OnInit } from '@angular/core';
import { CdkDragDrop } from '@angular/cdk/drag-drop/drag-events';
import { UnitPageSection } from '../../../../../../../common/unit';
import { UnitService } from '../../../../unit.service';
......@@ -21,13 +22,37 @@ import { UnitService } from '../../../../unit.service';
<div *ngIf="section.dynamicPositioning"
[style.display]="'grid'"
[style.grid-template-columns]="section.gridColumnSizes"
[style.height.%]="100">
[style.grid-template-rows]="section.gridRowSizes"
[style.height.%]="100"
cdkDropListGroup>
<ng-container *ngFor="let column of this.section.gridColumnSizes.split(' '); let x = index">
<ng-container *ngFor="let row of this.section.gridRowSizes.split(' '); let y = index">
<div [style.grid-column-start]="x + 1"
[style.grid-column-end]="x + 1"
[style.grid-row-start]="y + 1"
[style.grid-row-end]="y + 1"
[style.border]="'25px inset'"
cdkDropList [cdkDropListData]="[x + 1, y + 1]" (cdkDropListDropped)="drop($event)">
{{x + 1}} / {{y + 1}}
</div>
</ng-container>
</ng-container>
<app-dynamic-canvas-overlay *ngFor="let element of section.elements"
[element]="$any(element)"
[style.min-width.px]="element.width"
[style.min-height.px]="element.height"
[style.grid-column-start]="element.gridColumnStart"
[style.grid-column-end]="element.gridColumnEnd">
[style.grid-column-end]="element.gridColumnEnd"
[style.grid-row-start]="element.gridRowStart"
[style.grid-row-end]="element.gridRowEnd"
cdkDropList cdkDropListSortingDisabled
(resize)="resizeOverlay($event)"
[style.pointer-events]="dragging ? 'none' : 'auto'"
[style.position]="dragging ? 'absolute' : null"
[style.width.px]="dragging ? draggingElementWidth : null"
[style.height.px]="dragging ? draggingElementHeight : null">
</app-dynamic-canvas-overlay>
</div>
......@@ -46,7 +71,7 @@ import { UnitService } from '../../../../unit.service';
styles: [
'.sectionMenu {visibility: hidden; transition: 0.2s 0.7s;}',
'.section-wrapper:hover .sectionMenu {visibility: visible; transition-delay: 0s;}',
'.sectionMenu {position: absolute; left: -29px}',
'.sectionMenu {position: absolute; left: -29px; top: 0}',
'.sectionMenu button {width: 28px; height: 28px}',
'.sectionMenu .mat-mini-fab {line-height: 0;}',
'::ng-deep .sectionMenu .mat-mini-fab .mat-button-wrapper {line-height: 0;}'
......@@ -56,6 +81,9 @@ export class CanvasSectionComponent implements OnInit {
@Input() section!: UnitPageSection;
@Input() sectionIndex!: number;
selected = true;
dragging = false;
draggingElementWidth: number | undefined = 0;
draggingElementHeight: number | undefined = 0;
constructor(public unitService: UnitService) {
this.unitService.selectSection(this);
......@@ -64,4 +92,27 @@ export class CanvasSectionComponent implements OnInit {
ngOnInit(): void {
this.unitService.selectSection(this);
}
drop(event: CdkDragDrop<number[]>): void {
if (event.item.data.dragType === 'move') {
this.unitService.updateSelectedElementProperty('gridColumnStart', event.container.data[0]);
// Ensure the end value is at least the same as the start, otherwise the grid breaks
this.unitService.updateSelectedElementProperty(
'gridColumnEnd', Math.max(event.item.data.element.gridColumnEnd, event.container.data[0])
);
this.unitService.updateSelectedElementProperty('gridRowStart', event.container.data[1]);
this.unitService.updateSelectedElementProperty(
'gridRowEnd', Math.max(event.item.data.element.gridRowEnd, event.container.data[1])
);
} else { // resize
this.unitService.updateSelectedElementProperty('gridColumnEnd', event.container.data[0] + 1);
this.unitService.updateSelectedElementProperty('gridRowEnd', event.container.data[1] + 1);
}
}
resizeOverlay(event: { dragging: boolean, elementWidth?: number, elementHeight?: number }): void {
this.dragging = event.dragging;
this.draggingElementWidth = event.elementWidth;
this.draggingElementHeight = event.elementHeight;
}
}
import { Component, Input } from '@angular/core';
import {
Component, Input, Output, EventEmitter, ViewChild, ElementRef
} from '@angular/core';
import { CdkDragMove } from '@angular/cdk/drag-drop';
import { CanvasElementOverlay } from './canvas-element-overlay';
import { UnitUIElement } from '../../../../../../../common/unit';
@Component({
selector: 'app-dynamic-canvas-overlay',
template: `
<div class="draggable-element" [class.draggable-element-selected]="selected"
cdkDrag [cdkDragData]="this.element" [cdkDragDisabled]="!selected"
(click)="click($event)"
(dblclick)="openEditDialog()"
[style.height.%]="100">
<div #draggableElement class="draggable-element" [class.draggable-element-selected]="selected"
cdkDrag [cdkDragData]="{dragType: 'move', element: this.element}" [cdkDragDisabled]="!selected"
(click)="click($event)" (dblclick)="openEditDialog()"
[style.height.%]="100"
[style.border]="selected ? '1px solid' : ''">
<div *ngIf="selected" class="resizeHandle"
cdkDrag [cdkDragData]="{dragType: 'resize', element: this.element}"
(cdkDragStarted)="dragStart()" (cdkDragEnded)="dragEnd()" (cdkDragMoved)="resizeElement($event)"
[style.right.px]="2" [style.bottom.px]="-3">
<mat-icon>south_east</mat-icon>
<div *cdkDragPlaceholder></div>
</div>
<ng-template #elementContainer></ng-template>
</div>
`
`,
styles: [
'.draggable-element {position: relative}',
'.resizeHandle {position: absolute}'
]
})
export class DynamicCanvasOverlayComponent extends CanvasElementOverlay {
@Input() dynamicPositioning!: boolean;
@Output() resize = new EventEmitter<{ dragging: boolean, elementWidth?: number, elementHeight?: number }>();
@ViewChild('draggableElement') dragElement!: ElementRef;
private gridElementWidth: number = 0;
private gridElementHeight: number = 0;
dragStart(): void {
this.gridElementWidth = this.dragElement.nativeElement.offsetWidth - 2;
this.gridElementHeight = this.dragElement.nativeElement.offsetHeight - 2;
this.resize.emit({
dragging: true,
elementWidth: this.dragElement.nativeElement.offsetWidth - 2,
elementHeight: this.dragElement.nativeElement.offsetHeight - 2
});
}
resizeElement(event: CdkDragMove<{ dragType: string; element: UnitUIElement }>): void {
this.resize.emit({
dragging: true,
elementWidth: this.gridElementWidth + event.distance.x,
elementHeight: this.gridElementHeight + event.distance.y
});
}
dragEnd(): void {
this.resize.emit({
dragging: false
});
}
}
......@@ -30,6 +30,10 @@ import { UnitService } from '../../../../unit.service';
<mat-label>Grid-Spalten</mat-label>
<input matInput [(ngModel)]="selectedPageSection.gridColumnSizes">
</mat-form-field>
<mat-form-field>
<mat-label>Grid-Zeilen</mat-label>
<input matInput [(ngModel)]="selectedPageSection.gridRowSizes">
</mat-form-field>
</div>
<button mat-raised-button
(click)="unitService.deleteSelectedSection()">
......
......@@ -30,8 +30,9 @@ export function createUnitPageSection(): UnitPageSection {
width: 1100,
height: 200,
backgroundColor: '#FFFAF0',
dynamicPositioning: false,
gridColumnSizes: '1fr 1fr 1fr'
dynamicPositioning: true,
gridColumnSizes: '1fr 1fr',
gridRowSizes: '1fr'
};
}
......@@ -42,13 +43,13 @@ function createUnitUIElement(type: string): UnitUIElement {
zIndex: 0,
width: 180,
height: 60,
dynamicPositioning: false,
dynamicPositioning: true,
xPosition: 0,
yPosition: 0,
gridColumnStart: 1,
gridColumnEnd: 1,
gridColumnEnd: 2,
gridRowStart: 1,
gridRowEnd: 1
gridRowEnd: 2
};
}
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment