Skip to content

Commit f9355ee

Browse files
committed
[WIP] minSize with percent is working!
1 parent 2a0ca46 commit f9355ee

7 files changed

Lines changed: 195 additions & 144 deletions

File tree

projects/angular-split/src/lib/component/split.component.ts

Lines changed: 74 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -4,37 +4,35 @@ import { debounceTime } from 'rxjs/operators';
44

55
import { IArea, IPoint, ISplitSnapshot, IAreaSnapshot, ISplitSideAbsorptionCapacity, IOutputData, IOutputAreaSizes } from '../interface';
66
import { SplitAreaDirective } from '../directive/splitArea.directive';
7-
import { getInputPositiveNumber, getInputBoolean, getPointFromEvent, getElementPixelSize, getAreaAbsorptionCapacity, updateAreaSize, isUserSizesValid } from '../utils';
7+
import { getInputPositiveNumber, getInputBoolean, isUserSizesValid, getPointFromEvent, getElementPixelSize, getGutterSideAbsorptionCapacity, updateAreaSize } from '../utils';
88

99
/**
1010
* angular-split
1111
*
12-
* Areas size are set in percentage of the split container.
13-
* Gutters size are set in pixels.
1412
*
15-
* So we set css 'flex-basis' property like this (where 0 <= area.size <= 1):
16-
* calc( { area.size * 100 }% - { area.size * nbGutter * gutterSize }px );
13+
* PERCENT MODE ([unit]="'percent'")
14+
* ___________________________________________________________________________________________
15+
* | A [g1] B [g2] C [g3] D [g4] E |
16+
* |-------------------------------------------------------------------------------------------|
17+
* | 20 30 20 15 15 | <-- [size]="x"
18+
* | 10px 10px 10px 10px | <-- [gutterSize]="10"
19+
* |calc(20% - 8px) calc(30% - 12px) calc(20% - 8px) calc(15% - 6px) calc(15% - 6px)| <-- CSS flex-basis property (with flex-grow&shrink at 0)
20+
* | 152px 228px 152px 114px 114px | <-- el.getBoundingClientRect().width
21+
* |___________________________________________________________________________________________|
22+
* 800px <-- el.getBoundingClientRect().width
23+
* flex-basis = calc( { area.size }% - { area.size/100 * nbGutter*gutterSize }px );
1724
*
18-
* Examples with 3 visible areas and 2 gutters:
1925
*
20-
* | 10px 10px |
21-
* |---------------------[]---------------------[]------------------------------------|
22-
* | calc(20% - 4px) calc(20% - 4px) calc(60% - 12px) |
23-
*
24-
*
25-
* | 10px 10px |
26-
* |--------------------------[]--------------------------[]--------------------------|
27-
* | calc(33.33% - 6.667px) calc(33.33% - 6.667px) calc(33.33% - 6.667px) |
28-
*
29-
*
30-
* |10px 10px |
31-
* |[]----------------------------------------------------[]--------------------------|
32-
* |0 calc(66.66% - 13.333px) calc(33%% - 6.667px) |
33-
*
34-
*
35-
* 10px 10px |
36-
* |[][]------------------------------------------------------------------------------|
37-
* |0 0 calc(100% - 20px) |
26+
* PIXEL MODE ([unit]="'pixel'")
27+
* ___________________________________________________________________________________________
28+
* | A [g1] B [g2] C [g3] D [g4] E |
29+
* |-------------------------------------------------------------------------------------------|
30+
* | 100 250 * 150 100 | <-- [size]="y"
31+
* | 10px 10px 10px 10px | <-- [gutterSize]="10"
32+
* | 0 0 100px 0 0 250px 1 1 auto 0 0 150px 0 0 100px | <-- CSS flex property (flex-grow/flex-shrink/flex-basis)
33+
* | 100px 250px 200px 150px 100px | <-- el.getBoundingClientRect().width
34+
* |___________________________________________________________________________________________|
35+
* 800px <-- el.getBoundingClientRect().width
3836
*
3937
*/
4038

@@ -287,7 +285,7 @@ export class SplitComponent implements AfterViewInit, OnDestroy {
287285
}
288286

289287
public getVisibleAreaSizes(): IOutputAreaSizes {
290-
return this.displayedAreas.map(a => a.size || '*');
288+
return this.displayedAreas.map(a => a.size === null ? '*' : a.size);
291289
}
292290

293291
public setVisibleAreaSizes(sizes: IOutputAreaSizes): boolean {
@@ -380,22 +378,34 @@ export class SplitComponent implements AfterViewInit, OnDestroy {
380378

381379
private refreshStyleSizes(): void {
382380
if(this.displayedAreas.length === 1) {
383-
this.displayedAreas[0].component.setStyleFlex(`0 0 100%`);
381+
this.displayedAreas[0].component.setStyleFlex(`0 0 100%`, false, false);
384382
}
385383
else if(this.unit === 'percent') {
386384
const sumGutterSize = this.getNbGutters() * this.gutterSize;
387385

388386
this.displayedAreas.forEach(area => {
389-
area.component.setStyleFlex(`0 0 calc( ${ area.size }% - ${ <number> area.size / 100 * sumGutterSize }px )`);
387+
area.component.setStyleFlex(
388+
`0 0 calc( ${ area.size }% - ${ <number> area.size / 100 * sumGutterSize }px )`,
389+
area.minSize !== null && area.minSize === area.size ? true : false,
390+
area.maxSize !== null && area.maxSize === area.size ? true : false,
391+
);
390392
});
391393
}
392394
else if(this.unit === 'pixel') {
393395
this.displayedAreas.forEach(area => {
394396
if(area.size === null) {
395-
area.component.setStyleFlex(`1 1 auto`);
397+
area.component.setStyleFlex(
398+
`1 1 auto`,
399+
area.minSize !== null && area.minSize === area.size ? true : false,
400+
area.maxSize !== null && area.maxSize === area.size ? true : false,
401+
);
396402
}
397403
else {
398-
area.component.setStyleFlex(`0 0 ${ area.size }px`);
404+
area.component.setStyleFlex(
405+
`0 0 ${ area.size }px`,
406+
area.minSize !== null && area.minSize === area.size ? true : false,
407+
area.maxSize !== null && area.maxSize === area.size ? true : false,
408+
);
399409
}
400410
});
401411
}
@@ -427,7 +437,7 @@ export class SplitComponent implements AfterViewInit, OnDestroy {
427437
this.snapshot = {
428438
gutterNum,
429439
lastSteppedOffset: 0,
430-
containerSizePixel: getElementPixelSize(this.elRef, this.direction),
440+
allAreasSizePixel: getElementPixelSize(this.elRef, this.direction) - this.getNbGutters() * this.gutterSize,
431441
areasBeforeGutter: [],
432442
areasAfterGutter: [],
433443
};
@@ -498,24 +508,44 @@ export class SplitComponent implements AfterViewInit, OnDestroy {
498508

499509
// Need to know if each gutter side areas could reacts to steppedOffset
500510

501-
const areasBefore: ISplitSideAbsorptionCapacity = this.snapshot.areasBeforeGutter.reduce((acc, area) => {
502-
const res = getAreaAbsorptionCapacity(this.unit, area, acc.remain, this.snapshot.containerSizePixel);
503-
acc.list.push(res);
504-
acc.remain = res.pixelRemain;
505-
return acc;
506-
}, {remain: -steppedOffset, list: []});
511+
let areasBefore = getGutterSideAbsorptionCapacity(this.unit, this.snapshot.areasBeforeGutter, -steppedOffset, this.snapshot.allAreasSizePixel);
512+
let areasAfter = getGutterSideAbsorptionCapacity(this.unit, this.snapshot.areasAfterGutter, steppedOffset, this.snapshot.allAreasSizePixel);
513+
514+
// Each gutter side areas can't absorb all offset
515+
if(areasBefore.remain !== 0 && areasAfter.remain !== 0) {
516+
console.log('Case AAA > before=', areasBefore, ' - after=', areasAfter)
517+
if(Math.abs(areasBefore.remain) > Math.abs(areasAfter.remain)) {
518+
519+
}
520+
else {
521+
522+
}
523+
}
524+
// Areas before gutter can't absorbs all offset > need to recalculate sizes for areas after gutter.
525+
else if(areasBefore.remain !== 0) {
526+
console.log('Case BBB > before=', areasBefore.remain)
527+
areasAfter = getGutterSideAbsorptionCapacity(this.unit, this.snapshot.areasAfterGutter, steppedOffset + areasBefore.remain, this.snapshot.allAreasSizePixel);
528+
}
529+
// Areas after gutter can't absorbs all offset > need to recalculate sizes for areas before gutter.
530+
else if(areasAfter.remain !== 0) {
531+
console.log('Case CCC > after=', areasAfter.remain)
532+
areasBefore = getGutterSideAbsorptionCapacity(this.unit, this.snapshot.areasBeforeGutter, -(steppedOffset - areasAfter.remain), this.snapshot.allAreasSizePixel);
533+
}
534+
535+
// Hack to force total === 100
536+
if(this.unit === 'percent') {
537+
// get first area not at min/max and set size to 100-allAreaSizes
538+
const areaToReset = this.displayedAreas.find(a => a.size !== 0 && a.size !== a.minSize && a.size !== a.maxSize);
539+
540+
areaToReset.size = 100 - this.displayedAreas.filter(a => a !== areaToReset).reduce((total, a) => total+a.size, 0);
541+
}
542+
507543

508-
const areasAfter: ISplitSideAbsorptionCapacity = this.snapshot.areasAfterGutter.reduce((acc, area) => {
509-
const res = getAreaAbsorptionCapacity(this.unit, area, acc.remain, this.snapshot.containerSizePixel);
510-
acc.list.push(res);
511-
acc.remain = res.pixelRemain;
512-
return acc;
513-
}, {remain: steppedOffset, list: []});
544+
const tt = [...areasBefore.list.map(a=>a.percentAfterAbsorption), ...areasAfter.list.map(a=>a.percentAfterAbsorption)].reduce((t,s)=>t+s, 0);
545+
if(tt !== 100) debugger;
514546

515547
// Now we know areas could absorb steppedOffset, time to really update sizes
516548

517-
console.log('A', areasBefore.list[0].pixelAbsorb, areasBefore.list[0].percentAfterAbsorption);
518-
console.log('B', areasAfter.list[0].pixelAbsorb, areasAfter.list[0].percentAfterAbsorption);
519549
areasBefore.list.forEach(item => updateAreaSize(this.unit, item));
520550
areasAfter.list.forEach(item => updateAreaSize(this.unit, item));
521551

projects/angular-split/src/lib/directive/splitArea.directive.ts

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,8 +112,14 @@ export class SplitAreaDirective implements OnInit, OnDestroy {
112112
this.renderer.setStyle(this.elRef.nativeElement, 'order', value);
113113
}
114114

115-
public setStyleFlex(value: string): void {
115+
public setStyleFlex(value: string, isMin: boolean, isMax: boolean): void {
116116
this.renderer.setStyle(this.elRef.nativeElement, 'flex', value);
117+
118+
if(isMin === true) this.renderer.addClass(this.elRef.nativeElement, 'as-min');
119+
else this.renderer.removeClass(this.elRef.nativeElement, 'as-min');
120+
121+
if(isMax === true) this.renderer.addClass(this.elRef.nativeElement, 'as-max');
122+
else this.renderer.removeClass(this.elRef.nativeElement, 'as-max');
117123
}
118124

119125
public lockEvents(): void {

projects/angular-split/src/lib/interface.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ export interface IArea {
1717

1818
export interface ISplitSnapshot {
1919
gutterNum: number
20-
containerSizePixel: number
20+
allAreasSizePixel: number
2121
lastSteppedOffset: number
2222
areasBeforeGutter: Array<IAreaSnapshot>
2323
areasAfterGutter: Array<IAreaSnapshot>

projects/angular-split/src/lib/service/UndetectedEventPlugin.ts

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,10 @@ export class UndetectedEventPlugin {
1010
manager: EventManager;
1111

1212
supports(eventName: string): boolean {
13-
console.log('SUPPROT ? eventName', eventName)
1413
return eventName.indexOf('undetected.') === 0;
1514
}
1615

1716
addEventListener(element: HTMLElement, eventName: string, handler: Function): Function {
18-
console.log('addEventListener > eventName', eventName)
1917
const realEventName = eventName.slice(11);
2018

2119
return this.manager.getZone().runOutsideAngular(() => this.manager.addEventListener(element, realEventName, handler));

projects/angular-split/src/lib/utils.ts

Lines changed: 24 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
import { ElementRef } from '@angular/core';
22

3-
import { IPoint, IAreaSnapshot, IAreaAbsorptionCapacity } from './interface';
3+
import { IPoint, IAreaSnapshot, ISplitSideAbsorptionCapacity, IAreaAbsorptionCapacity } from './interface';
44

55
export function getPointFromEvent(event: MouseEvent | TouchEvent): IPoint {
66
// TouchEvent
@@ -48,19 +48,28 @@ export function isUserSizesValid(unit: 'percent' | 'pixel', sizes: Array<number
4848
}
4949
}
5050

51-
export function getAreaAbsorptionCapacity(unit: 'percent' | 'pixel', areaSnapshot: IAreaSnapshot, pixels: number, containerSizePixel: number): IAreaAbsorptionCapacity {
51+
export function getGutterSideAbsorptionCapacity(unit: 'percent' | 'pixel', sideAreas: Array<IAreaSnapshot>, pixels: number, allAreasSizePixel: number): ISplitSideAbsorptionCapacity {
52+
return sideAreas.reduce((acc, area) => {
53+
const res = getAreaAbsorptionCapacity(unit, area, acc.remain, allAreasSizePixel);
54+
acc.list.push(res);
55+
acc.remain = res.pixelRemain;
56+
return acc;
57+
}, {remain: pixels, list: []});
58+
}
59+
60+
function getAreaAbsorptionCapacity(unit: 'percent' | 'pixel', areaSnapshot: IAreaSnapshot, pixels: number, allAreasSizePixel: number): IAreaAbsorptionCapacity {
5261
// No pain no gain
5362
if(pixels === 0) {
5463
return {
5564
areaSnapshot,
5665
pixelAbsorb: 0,
57-
percentAfterAbsorption: 0,
66+
percentAfterAbsorption: areaSnapshot.sizePercentAtStart,
5867
pixelRemain: 0,
5968
};
6069
}
6170

62-
// Area at zero and need to be reduced, not possible
63-
if(areaSnapshot.area.size === 0 && pixels < 0) {
71+
// Area start at zero and need to be reduced, not possible
72+
if(areaSnapshot.sizePixelAtStart === 0 && pixels < 0) {
6473
return {
6574
areaSnapshot,
6675
pixelAbsorb: 0,
@@ -70,16 +79,17 @@ export function getAreaAbsorptionCapacity(unit: 'percent' | 'pixel', areaSnapsho
7079
}
7180

7281
if(unit === 'pixel') {
73-
return getAreaAbsorptionCapacityPixel(areaSnapshot, pixels, containerSizePixel);
82+
return getAreaAbsorptionCapacityPixel(areaSnapshot, pixels, allAreasSizePixel);
7483
}
75-
else if(unit === 'percent') {
76-
return getAreaAbsorptionCapacityPercent(areaSnapshot, pixels, containerSizePixel);
84+
85+
if(unit === 'percent') {
86+
return getAreaAbsorptionCapacityPercent(areaSnapshot, pixels, allAreasSizePixel);
7787
}
7888
}
7989

80-
function getAreaAbsorptionCapacityPercent(areaSnapshot: IAreaSnapshot, pixels: number, containerSizePixel: number): IAreaAbsorptionCapacity {
90+
function getAreaAbsorptionCapacityPercent(areaSnapshot: IAreaSnapshot, pixels: number, allAreasSizePixel: number): IAreaAbsorptionCapacity {
8191
const tempPixelSize = areaSnapshot.sizePixelAtStart + pixels;
82-
const tempPercentSize = tempPixelSize / areaSnapshot.sizePixelAtStart * areaSnapshot.sizePercentAtStart;
92+
const tempPercentSize = tempPixelSize / allAreasSizePixel * 100;
8393

8494
// ENLARGE AREA
8595

@@ -95,15 +105,6 @@ function getAreaAbsorptionCapacityPercent(areaSnapshot: IAreaSnapshot, pixels: n
95105
pixelRemain: pixels - maxPixelAbsorb
96106
};
97107
}
98-
else if(areaSnapshot.sizePixelAtStart === 0) {
99-
console.log('TODO percentAfterAbsorption', (pixels / containerSizePixel * 100))
100-
return {
101-
areaSnapshot,
102-
pixelAbsorb: pixels,
103-
percentAfterAbsorption: pixels / containerSizePixel * 100,
104-
pixelRemain: pixels,
105-
};
106-
}
107108
return {
108109
areaSnapshot,
109110
pixelAbsorb: pixels,
@@ -118,12 +119,12 @@ function getAreaAbsorptionCapacityPercent(areaSnapshot: IAreaSnapshot, pixels: n
118119
// If minSize & newSize smaller than it > absorb to min and return remaining pixels
119120
if(areaSnapshot.area.minSize !== null && tempPercentSize < areaSnapshot.area.minSize) {
120121
// Use area.area.minSize as newPercentSize and return calculate pixels remaining
121-
const maxPixelAbsorb = areaSnapshot.sizePixelAtStart * areaSnapshot.area.minSize / areaSnapshot.sizePercentAtStart;
122+
const minSizePixel = areaSnapshot.area.minSize / 100 * allAreasSizePixel;
122123
return {
123124
areaSnapshot,
124-
pixelAbsorb: maxPixelAbsorb,
125-
percentAfterAbsorption: (areaSnapshot.sizePixelAtStart + maxPixelAbsorb) / areaSnapshot.sizePixelAtStart * areaSnapshot.sizePercentAtStart,
126-
pixelRemain: pixels - maxPixelAbsorb
125+
pixelAbsorb: minSizePixel,
126+
percentAfterAbsorption: areaSnapshot.area.minSize,
127+
pixelRemain: areaSnapshot.sizePixelAtStart + pixels - minSizePixel
127128
};
128129
}
129130
// If reduced under zero > return remaining pixels

0 commit comments

Comments
 (0)