Skip to content

Commit

Permalink
fix(grid-component): improve end of drag events of the grid elements,…
Browse files Browse the repository at this point in the history
… animate over other elements

refactor(grid-component): added useful comments on 'addGridItemAnimatingClass'
  • Loading branch information
jvquarck authored and llorenspujol committed Sep 7, 2023
1 parent bb8598b commit 251c1bb
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 2 deletions.
2 changes: 1 addition & 1 deletion projects/angular-grid-layout/src/lib/grid.component.scss
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ ktd-grid {
}

ktd-grid-item {
&.ktd-grid-item-dragging {
&.ktd-grid-item-dragging, &.ktd-grid-item-animating {
z-index: 1000;
}

Expand Down
43 changes: 42 additions & 1 deletion projects/angular-grid-layout/src/lib/grid.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {
} from '@angular/core';
import { coerceNumberProperty, NumberInput } from './coercion/number-property';
import { KtdGridItemComponent } from './grid-item/grid-item.component';
import { combineLatest, merge, NEVER, Observable, Observer, of, Subscription } from 'rxjs';
import { combineLatest, empty, merge, NEVER, Observable, Observer, of, Subscription } from 'rxjs';
import { exhaustMap, map, startWith, switchMap, takeUntil } from 'rxjs/operators';
import { ktdGetGridItemRowHeight, ktdGridItemDragging, ktdGridItemLayoutItemAreEqual, ktdGridItemResizing } from './utils/grid.utils';
import { compact } from './utils/react-grid-layout.utils';
Expand All @@ -19,6 +19,7 @@ import { getMutableClientRect, KtdClientRect } from './utils/client-rect';
import { ktdGetScrollTotalRelativeDifference$, ktdScrollIfNearElementClientRect$ } from './utils/scroll';
import { BooleanInput, coerceBooleanProperty } from './coercion/boolean-property';
import { KtdGridItemPlaceholder } from './directives/placeholder';
import { getTransformTransitionDurationInMs } from './utils/transition-duration';

interface KtdDragResizeEvent {
layout: KtdGridLayout;
Expand Down Expand Up @@ -272,6 +273,7 @@ export class KtdGridComponent implements OnChanges, AfterContentInit, AfterConte
get backgroundConfig(): KtdGridBackgroundCfg | null {
return this._backgroundConfig;
}

set backgroundConfig(val: KtdGridBackgroundCfg | null) {
this._backgroundConfig = val;

Expand Down Expand Up @@ -611,6 +613,8 @@ export class KtdGridComponent implements OnChanges, AfterContentInit, AfterConte
this.renderer.removeClass(gridItem.elementRef.nativeElement, 'no-transitions');
this.renderer.removeClass(gridItem.elementRef.nativeElement, 'ktd-grid-item-dragging');

this.addGridItemAnimatingClass(gridItem).subscribe();
// Consider destroying the placeholder after the animation has finished.
this.destroyPlaceholder();

if (newLayout) {
Expand Down Expand Up @@ -645,6 +649,43 @@ export class KtdGridComponent implements OnChanges, AfterContentInit, AfterConte
});
}


/**
* It adds the `ktd-grid-item-animating` class and removes it when the animated transition is complete.
* This function is meant to be executed when the drag has ended.
* @param gridItem that has been dragged
*/
private addGridItemAnimatingClass(gridItem: KtdGridItemComponent): Observable<undefined> {

return new Observable(observer => {

const duration = getTransformTransitionDurationInMs(gridItem.elementRef.nativeElement);

if (duration === 0) {
observer.next();
observer.complete();
return;
}

this.renderer.addClass(gridItem.elementRef.nativeElement, 'ktd-grid-item-animating');
const handler = ((event: TransitionEvent) => {
if (!event || (event.target === gridItem.elementRef.nativeElement && event.propertyName === 'transform')) {
this.renderer.removeClass(gridItem.elementRef.nativeElement, 'ktd-grid-item-animating');
removeEventListener();
clearTimeout(timeout);
observer.next();
observer.complete();
}
}) as EventListener;

// If a transition is short enough, the browser might not fire the `transitionend` event.
// Since we know how long it's supposed to take, add a timeout with a 50% buffer that'll
// fire if the transition hasn't completed when it was supposed to.
const timeout = setTimeout(handler, duration * 1.5);
const removeEventListener = this.renderer.listen(gridItem.elementRef.nativeElement, 'transitionend', handler);
})
}

/** Creates placeholder element */
private createPlaceholderElement(clientRect: KtdClientRect, gridItemPlaceholder?: KtdGridItemPlaceholder) {
this.placeholder = this.renderer.createElement('div');
Expand Down
40 changes: 40 additions & 0 deletions projects/angular-grid-layout/src/lib/utils/transition-duration.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
/**
* Transition duration utilities.
* This file is taken from Angular Material repository.
*/

/* eslint-disable @katoid/prefix-exported-code */

/** Parses a CSS time value to milliseconds. */
function parseCssTimeUnitsToMs(value: string): number {
// Some browsers will return it in seconds, whereas others will return milliseconds.
const multiplier = value.toLowerCase().indexOf('ms') > -1 ? 1 : 1000;
return parseFloat(value) * multiplier;
}

/** Gets the transform transition duration, including the delay, of an element in milliseconds. */
export function getTransformTransitionDurationInMs(element: HTMLElement): number {
const computedStyle = getComputedStyle(element);
const transitionedProperties = parseCssPropertyValue(computedStyle, 'transition-property');
const property = transitionedProperties.find(prop => prop === 'transform' || prop === 'all');

// If there's no transition for `all` or `transform`, we shouldn't do anything.
if (!property) {
return 0;
}

// Get the index of the property that we're interested in and match
// it up to the same index in `transition-delay` and `transition-duration`.
const propertyIndex = transitionedProperties.indexOf(property);
const rawDurations = parseCssPropertyValue(computedStyle, 'transition-duration');
const rawDelays = parseCssPropertyValue(computedStyle, 'transition-delay');

return parseCssTimeUnitsToMs(rawDurations[propertyIndex]) +
parseCssTimeUnitsToMs(rawDelays[propertyIndex]);
}

/** Parses out multiple values from a computed style into an array. */
function parseCssPropertyValue(computedStyle: CSSStyleDeclaration, name: string): string[] {
const value = computedStyle.getPropertyValue(name);
return value.split(',').map(part => part.trim());
}

0 comments on commit 251c1bb

Please sign in to comment.