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 { ...@@ -21,6 +21,7 @@ export interface UnitPageSection {
backgroundColor: string; backgroundColor: string;
dynamicPositioning: boolean; dynamicPositioning: boolean;
gridColumnSizes: string; gridColumnSizes: string;
gridRowSizes: string;
} }
export interface UnitUIElement { export interface UnitUIElement {
......
import { Component, Input, OnInit } from '@angular/core'; import { Component, Input, OnInit } from '@angular/core';
import { CdkDragDrop } from '@angular/cdk/drag-drop/drag-events';
import { UnitPageSection } from '../../../../../../../common/unit'; import { UnitPageSection } from '../../../../../../../common/unit';
import { UnitService } from '../../../../unit.service'; import { UnitService } from '../../../../unit.service';
...@@ -21,13 +22,37 @@ import { UnitService } from '../../../../unit.service'; ...@@ -21,13 +22,37 @@ import { UnitService } from '../../../../unit.service';
<div *ngIf="section.dynamicPositioning" <div *ngIf="section.dynamicPositioning"
[style.display]="'grid'" [style.display]="'grid'"
[style.grid-template-columns]="section.gridColumnSizes" [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" <app-dynamic-canvas-overlay *ngFor="let element of section.elements"
[element]="$any(element)" [element]="$any(element)"
[style.min-width.px]="element.width" [style.min-width.px]="element.width"
[style.min-height.px]="element.height" [style.min-height.px]="element.height"
[style.grid-column-start]="element.gridColumnStart" [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> </app-dynamic-canvas-overlay>
</div> </div>
...@@ -46,7 +71,7 @@ import { UnitService } from '../../../../unit.service'; ...@@ -46,7 +71,7 @@ import { UnitService } from '../../../../unit.service';
styles: [ styles: [
'.sectionMenu {visibility: hidden; transition: 0.2s 0.7s;}', '.sectionMenu {visibility: hidden; transition: 0.2s 0.7s;}',
'.section-wrapper:hover .sectionMenu {visibility: visible; transition-delay: 0s;}', '.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 button {width: 28px; height: 28px}',
'.sectionMenu .mat-mini-fab {line-height: 0;}', '.sectionMenu .mat-mini-fab {line-height: 0;}',
'::ng-deep .sectionMenu .mat-mini-fab .mat-button-wrapper {line-height: 0;}' '::ng-deep .sectionMenu .mat-mini-fab .mat-button-wrapper {line-height: 0;}'
...@@ -56,6 +81,9 @@ export class CanvasSectionComponent implements OnInit { ...@@ -56,6 +81,9 @@ export class CanvasSectionComponent implements OnInit {
@Input() section!: UnitPageSection; @Input() section!: UnitPageSection;
@Input() sectionIndex!: number; @Input() sectionIndex!: number;
selected = true; selected = true;
dragging = false;
draggingElementWidth: number | undefined = 0;
draggingElementHeight: number | undefined = 0;
constructor(public unitService: UnitService) { constructor(public unitService: UnitService) {
this.unitService.selectSection(this); this.unitService.selectSection(this);
...@@ -64,4 +92,27 @@ export class CanvasSectionComponent implements OnInit { ...@@ -64,4 +92,27 @@ export class CanvasSectionComponent implements OnInit {
ngOnInit(): void { ngOnInit(): void {
this.unitService.selectSection(this); 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 { CanvasElementOverlay } from './canvas-element-overlay';
import { UnitUIElement } from '../../../../../../../common/unit';
@Component({ @Component({
selector: 'app-dynamic-canvas-overlay', selector: 'app-dynamic-canvas-overlay',
template: ` template: `
<div class="draggable-element" [class.draggable-element-selected]="selected" <div #draggableElement class="draggable-element" [class.draggable-element-selected]="selected"
cdkDrag [cdkDragData]="this.element" [cdkDragDisabled]="!selected" cdkDrag [cdkDragData]="{dragType: 'move', element: this.element}" [cdkDragDisabled]="!selected"
(click)="click($event)" (click)="click($event)" (dblclick)="openEditDialog()"
(dblclick)="openEditDialog()" [style.height.%]="100"
[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> <ng-template #elementContainer></ng-template>
</div> </div>
` `,
styles: [
'.draggable-element {position: relative}',
'.resizeHandle {position: absolute}'
]
}) })
export class DynamicCanvasOverlayComponent extends CanvasElementOverlay { export class DynamicCanvasOverlayComponent extends CanvasElementOverlay {
@Input() dynamicPositioning!: boolean; @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'; ...@@ -30,6 +30,10 @@ import { UnitService } from '../../../../unit.service';
<mat-label>Grid-Spalten</mat-label> <mat-label>Grid-Spalten</mat-label>
<input matInput [(ngModel)]="selectedPageSection.gridColumnSizes"> <input matInput [(ngModel)]="selectedPageSection.gridColumnSizes">
</mat-form-field> </mat-form-field>
<mat-form-field>
<mat-label>Grid-Zeilen</mat-label>
<input matInput [(ngModel)]="selectedPageSection.gridRowSizes">
</mat-form-field>
</div> </div>
<button mat-raised-button <button mat-raised-button
(click)="unitService.deleteSelectedSection()"> (click)="unitService.deleteSelectedSection()">
......
...@@ -30,8 +30,9 @@ export function createUnitPageSection(): UnitPageSection { ...@@ -30,8 +30,9 @@ export function createUnitPageSection(): UnitPageSection {
width: 1100, width: 1100,
height: 200, height: 200,
backgroundColor: '#FFFAF0', backgroundColor: '#FFFAF0',
dynamicPositioning: false, dynamicPositioning: true,
gridColumnSizes: '1fr 1fr 1fr' gridColumnSizes: '1fr 1fr',
gridRowSizes: '1fr'
}; };
} }
...@@ -42,13 +43,13 @@ function createUnitUIElement(type: string): UnitUIElement { ...@@ -42,13 +43,13 @@ function createUnitUIElement(type: string): UnitUIElement {
zIndex: 0, zIndex: 0,
width: 180, width: 180,
height: 60, height: 60,
dynamicPositioning: false, dynamicPositioning: true,
xPosition: 0, xPosition: 0,
yPosition: 0, yPosition: 0,
gridColumnStart: 1, gridColumnStart: 1,
gridColumnEnd: 1, gridColumnEnd: 2,
gridRowStart: 1, 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