Skip to content

Commit

Permalink
feat: support curve and line path
Browse files Browse the repository at this point in the history
  • Loading branch information
HandsomeButterball committed Mar 3, 2022
1 parent fd2ee4d commit 580392d
Show file tree
Hide file tree
Showing 13 changed files with 311 additions and 120 deletions.
1 change: 1 addition & 0 deletions example/src/app/gantt/gantt.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
[childrenResolve]="childrenResolve"
[draggable]="true"
[linkable]="true"
[linkOptions]="linkOptions"
[viewOptions]="viewOptions"
(barClick)="barClick($event)"
(lineClick)="lineClick($event)"
Expand Down
12 changes: 9 additions & 3 deletions example/src/app/gantt/gantt.component.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { GanttLinkPathType } from './../../../../packages/gantt/src/class/link';
import { Component, OnInit, HostBinding, ViewChild } from '@angular/core';
import {
GanttBarClickEvent,
Expand Down Expand Up @@ -68,8 +69,8 @@ export class AppGanttExampleComponent implements OnInit {
start: 1624705997,
expandable: true,
links: [
{ type: 1, link: '000001' },
{ type: 1, link: '000003' }
// { type: 1, link: '000001' },
{ type: 3, link: '000005' }
]
},
{
Expand All @@ -79,7 +80,7 @@ export class AppGanttExampleComponent implements OnInit {
end: 1629544397,
color: '#709dc1',
links: [
{ type: 3, link: '000004' },
{ type: 4, link: '000004' },
{ type: 2, link: '000003' }
]
},
Expand Down Expand Up @@ -119,6 +120,11 @@ export class AppGanttExampleComponent implements OnInit {
}
};

linkOptions = {
showArrow: true,
linkPathType: GanttLinkPathType.line
}

@HostBinding('class.gantt-example-component') class = true;

@ViewChild('gantt') ganttComponent: NgxGanttComponent;
Expand Down
14 changes: 13 additions & 1 deletion packages/gantt/src/class/link.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ export enum GanttLinkType {
sf = 4
}

export enum GanttLinkPathType {
curve = 'curve',
line = 'line'
}

export enum LinkColors {
default = '#cacaca',
blocked = '#FF7575',
Expand All @@ -17,6 +22,7 @@ export enum LinkColors {
export interface GanttLink {
type: GanttLinkType;
link: string;
color?: string;
}

export interface GanttLinkItem {
Expand All @@ -33,6 +39,12 @@ export interface LinkInternal {
path: string;
source: GanttItem;
target: GanttItem;
color: LinkColors;
color: string;
type: GanttLinkType;
}

export interface GanttLinkOptions {
dependencyTypes?: [GanttLinkType.fs];
showArrow?: false;
linkPathType?: GanttLinkPathType.curve;
}
23 changes: 19 additions & 4 deletions packages/gantt/src/components/links/links.component.html
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
stroke-width="2"
[attr.stroke]="link.color"
pointer-events="none"
[style]="'marker-end: url(#triangle' + i + ')'"
[attr.style]="link.type === ganttLinkTypes.sf ? 'marker-start: url(#triangle' + i + ')' : 'marker-end: url(#triangle' + i + ')'"
></path>
<g>
<path
Expand All @@ -21,11 +21,26 @@
cursor="pointer"
></path>
</g>
<!-- <defs>
<marker [id]="'triangle' + i" markerUnits="strokeWidth" markerWidth="5" markerHeight="4" refX="5" refY="2" orient="auto">
<defs *ngIf="showArrow">
<marker
*ngIf="link.type === ganttLinkTypes.sf; else markerEnd"
[id]="'triangle' + i"
markerUnits="strokeWidth"
markerWidth="5"
markerHeight="4"
refX="5"
refY="2"
orient="180"
>
<path [attr.fill]="link.color" [attr.stroke]="link.color" d="M 0 0 L 5 2 L 0 4 z" />
</marker>
</defs> -->

<ng-template #markerEnd>
<marker [id]="'triangle' + i" markerUnits="strokeWidth" markerWidth="5" markerHeight="4" refX="5" refY="2" orient="auto">
<path [attr.fill]="link.color" [attr.stroke]="link.color" d="M 0 0 L 5 2 L 0 4 z" />
</marker>
</ng-template>
</defs>
</ng-container>
<line class="link-dragging-line"></line>
</svg>
125 changes: 17 additions & 108 deletions packages/gantt/src/components/links/links.component.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@ import { GanttDragContainer } from '../../gantt-drag-container';
import { recursiveItems } from '../../utils/helpers';
import { GANTT_UPPER_TOKEN, GanttUpper } from '../../gantt-upper';
import { GanttLinkItem, LinkInternal, LinkColors, GanttLinkType } from '../../class/link';
import { GanttLinkPath } from './paths/path';
import { generatePathFactory } from './paths/factory';

@Component({
selector: 'gantt-links-overlay',
Expand All @@ -34,12 +36,16 @@ export class GanttLinksComponent implements OnInit, OnChanges, OnDestroy {

public links: LinkInternal[] = [];

private linkItems: GanttLinkItem[] = [];
public ganttLinkTypes = GanttLinkType;

public showArrow = false;

private bezierWeight = -0.5;
private linkItems: GanttLinkItem[] = [];

private firstChange = true;

private linkPath: GanttLinkPath;

private unsubscribe$ = new Subject();

@HostBinding('class.gantt-links-overlay') ganttLinksOverlay = true;
Expand All @@ -52,6 +58,9 @@ export class GanttLinksComponent implements OnInit, OnChanges, OnDestroy {
) {}

ngOnInit() {
this.linkPath = generatePathFactory(this.ganttUpper.linkOptions.linkPathType, this.ganttUpper);

this.showArrow = this.ganttUpper.linkOptions.showArrow;
this.buildLinks();
this.firstChange = false;

Expand Down Expand Up @@ -127,110 +136,6 @@ export class GanttLinksComponent implements OnInit, OnChanges, OnDestroy {
}
}

private generatePath(source: GanttLinkItem, target: GanttLinkItem, type: GanttLinkType) {
if (source.before && source.after && target.before && target.after) {
let x1 = source.after.x;
let y1 = source.after.y;
let x4 = target.before.x;
let y4 = target.before.y;
let isMirror: number;
const control = Math.abs(y4 - y1) / 2;

switch (type) {
case GanttLinkType.ss:
x1 = source.before.x;
y1 = source.before.y;
x4 = target.before.x;
y4 = target.before.y;
isMirror = y4 > y1 ? 0 : 1;

if (x4 > x1) {
return `M ${x1} ${y1}
A ${control} ${control} 0 1 ${isMirror} ${x1} ${y4}
L ${x1} ${y4} ${x4} ${y4}`;
} else {
return `M ${x1} ${y1}
L ${x1} ${y1} ${x4} ${y1}
A ${control} ${control} 0 1 ${isMirror} ${x4} ${y4}`;
}

case GanttLinkType.ff:
x1 = source.after.x;
y1 = source.after.y;
x4 = target.after.x;
y4 = target.after.y;
isMirror = y4 > y1 ? 1 : 0;
if (x4 > x1) {
return `M ${x1} ${y1}
L ${x1} ${y1} ${x4} ${y1}
A ${control} ${control} 0 1 ${isMirror} ${x4} ${y4}`;
} else {
return `M ${x1} ${y1}
A ${control} ${control} 0 1 ${isMirror} ${x1} ${y4}
L ${x1} ${y4} ${x4} ${y4}`;
}

case GanttLinkType.sf:
x1 = target.after.x;
y1 = target.after.y;
x4 = source.before.x;
y4 = source.before.y;
}

const dx = Math.abs(x4 - x1) * this.bezierWeight;

const x2 = x1 - dx;
const x3 = x4 + dx;
const centerX = (x1 + x4) / 2;
const centerY = (y1 + y4) / 2;

let controlX = this.ganttUpper.styles.lineHeight / 2;
const controlY = this.ganttUpper.styles.lineHeight / 2;

if (x1 >= x4) {
if (y4 > y1) {
if (Math.abs(y4 - y1) <= this.ganttUpper.styles.lineHeight) {
return `M ${x1} ${y1}
C ${x1 + controlX} ${y1} ${x1 + controlX} ${y1 + controlX} ${x1} ${y1 + controlY}
L ${x1} ${y1 + controlY} ${centerX} ${centerY}
M ${x4} ${y4}
C ${x4 - controlX} ${y4} ${x4 - controlX} ${y4 - controlX} ${x4} ${y4 - controlY}
L ${x4} ${y4 - controlY} ${centerX} ${centerY}`;
} else {
controlX = this.ganttUpper.styles.lineHeight;
return `M ${x1} ${y1}
C ${x1 + controlX} ${y1} ${x1 + controlX} ${y1 + controlX} ${centerX} ${centerY}
M ${x4} ${y4}
C ${x4 - controlX} ${y4} ${x4 - controlX} ${y4 - controlX} ${centerX} ${centerY}`;
}
} else {
if (Math.abs(y4 - y1) <= this.ganttUpper.styles.lineHeight) {
return `M ${x1} ${y1}
C ${x1 + controlX} ${y1} ${x1 + controlX} ${y1 - controlX} ${x1} ${y1 - controlY}
L ${x1} ${y1 - controlY} ${centerX} ${centerY}
M ${x4} ${y4}
C ${x4 - controlX} ${y4} ${x4 - controlX} ${y4 + controlX} ${x4} ${y4 + controlY}
L ${x4} ${y4 + controlY} ${centerX} ${centerY}
`;
} else {
controlX = this.ganttUpper.styles.lineHeight;
return `M ${x1} ${y1}
C ${x1 + controlX} ${y1} ${x1 + controlX} ${y1 - controlX} ${centerX} ${centerY}
M ${x4} ${y4}
C ${x4 - controlX} ${y4} ${x4 - controlX} ${y4 + controlX} ${centerX} ${centerY}`;
}
}
}

return `M ${x1} ${y1} C ${x2} ${y1} ${x3} ${y4} ${x4} ${y4}`;
}
}

buildLinks() {
this.computeItemPosition();
this.links = [];
Expand All @@ -239,12 +144,16 @@ export class GanttLinksComponent implements OnInit, OnChanges, OnDestroy {
source.links.forEach((link) => {
const target = this.linkItems.find((item) => item.id === link.link);
if (target && (target.origin.start || target.origin.end)) {
let color = LinkColors.default;
if (link.type === GanttLinkType.fs && source.end.getTime() > target.start.getTime()) {
color = LinkColors.blocked;
}
this.links.push({
path: this.generatePath(source, target, link.type),
path: this.linkPath.generatePath(source, target, link.type),
source: source.origin,
target: target.origin,
type: link.type,
color: source.end.getTime() > target.start.getTime() ? LinkColors.blocked : LinkColors.default
color: link.color || color
});
}
});
Expand Down
Loading

0 comments on commit 580392d

Please sign in to comment.