ScheduleJS 1.4 release notes. A step forward towards modern Angular app building.
Générez des raccourcis et des interactions puissantes avec vos graphiques en créant un menu contextuel. Cet article propose une implémentation en quatre étapes d'un système de menu contextuel à partir de zéro dans vos graphiques ScheduleJS.
La première étape de ce tutoriel consiste à déclarer votre menu contextuel dans la partie HTML de l'application. La meilleure façon de garder votre code propre est de créer un composant dédié au rendu du menu contextuel et à la définition de vos interactions.
<!-- The ngStyle input will handle positionning -->
<div class="demo-planning-board-context-menu"
[class.display]="!gantt.contextMenuOverlay.isHidden"
[ngstyle]="gantt.contextMenuOverlay.position"
(click)="gantt.contextMenuOverlay.onHide()">
<!-- (1) Set started action -->
<div class="demo-planning-board-context-menu-action"
(click)="gantt.contextMenuOverlay.onSetTaskStarted()">
Set started
</div>
<!-- (2) Set completed action -->
<div class="demo-planning-board-context-menu-action"
(click)="gantt.contextMenuOverlay.onSetActivityCompleted()">
Set completed
</div>
<!-- (3) Set late action -->
<div class="demo-planning-board-context-menu-action"
(click)="gantt.contextMenuOverlay.onSetActivityLate()">
Set late
</div>
<!-- (4) Set priority action -->
<div class="demo-planning-board-context-menu-action"
(click)="gantt.contextMenuOverlay.onSetActivityPriority()">
{{ gantt.contextMenuOverlay.activity?.isHighPriority
? "Remove high priority" : "Set high priority" }}
</div>
</div> Le display sera utilisée pour cacher et afficher le menu contextuel, tandis que nous mettrons à jour sa position à l'aide de CSS et la ferons passer par la classe enfant Angular [ngStyle] propriété d'entrée.
Ici, nous avons créé une mise en page contextuelle simple avec quatre actions :
Set started: Modifier l'état de l'activité et la définir comme commencéeSet completed: Définir l'activité comme terminéeSet late: Définir la séquence d'activités comme tardive, à partir d'une activité spécifiqueSet priority: Définir la priorité comme élevée ou supprimer ce paramètreFaisons maintenant un peu de CSS pour rendre le tout plus joli. Nous recommandons d'utiliser SCSS pour créer une portée pour les classes de style comme suit :
.demo-planning-board-context-menu {
display: none;
position: absolute;
z-index: 1;
background: #555555dd;
border-radius: 5px;
padding: 3px 0;
&.display {
display: flex;
flex-direction: column;
}
.demo-planning-board-context-menu-action {
color: white;
font: 13px $demo-planning-board-font;
padding: 0 10px;
margin: 3px 0;
&:hover {
color: black;
filter: brightness(0.9);
background: rgba(255, 255, 255, 0.4);
}
&:active {
filter: brightness(0.8);
}
}
} Une fois cela fait, nous pouvons commencer à jouer avec Angular pour créer la logique de cet élément.
En utilisant une approche orientée objet, nous pouvons définir une abstraction qui sera le point de départ de toutes nos superpositions, de sorte que nous puissions la réutiliser pour créer des infobulles, des modales, etc.
export abstract class PlanningBoardAbstractOverlay {
// Attributes
isHidden: boolean = true;
activity: PlanningBoardActivity | undefined = undefined;
position: PlanningBoardOverlayPosition = {};
// Constructor
constructor(public gantt: PlanningBoardGanttChart) { }
// Methods
abstract onShow(pointerEvent: PointerEvent, activity: PlanningBoardActivity | undefined): void;
onHide(): void {
this.isHidden = true;
}
setOverlayElementPosition(pointerEvent: PointerEvent): void {
const isRight = pointerEvent.x > window.innerWidth / 2;
const isBottom = pointerEvent.y > window.innerHeight / 2;
const marginPx = 10;
this.position.top = isBottom ? "auto" : pointerEvent.y + marginPx + "px";
this.position.right = isRight ? window.innerWidth - pointerEvent.x + marginPx + "px" : "auto";
this.position.bottom = isBottom ? window.innerHeight - pointerEvent.y + marginPx + "px" : "auto";
this.position.left = isRight ? "auto" : pointerEvent.x + marginPx + "px";
}
}
export interface PlanningBoardOverlayPosition {
top?: string;
right?: string;
bottom?: string;
left?: string;
} Stockons quelques propriétés qui contiendront l'état de notre abstraction de superposition actuelle :
isHidden sera utilisée pour masquer et afficher le recouvrement.activity permet de relier notre superposition à une activité spécifique.position définira l'endroit où la superposition doit être rendue à l'aide de notre propriété PointerEvent.Exposer le GanttChart dans la superposition nous aidera à créer des actions et à interagir avec nos graphiques.
La superposition exposera également trois méthodes :
onShow est utilisée pour définir la stratégie d'affichage.onHide methode.setOverlayElementPosition mettra à jour le position propriété. En utilisant notre PlanningBoardAbstractOverlay nous pouvons maintenant créer une nouvelle classe abstraite PlanningBoardContextMenuOverlay qui contiendra la logique de notre menu contextuel.
export class PlanningBoardContextMenuOverlay extends PlanningBoardAbstractOverlay {
// Methods
onShow(pointerEvent: PointerEvent, activity: PlanningBoardActivity): void {
if (activity) {
this.isHidden = false;
this.activity = activity;
this.setOverlayElementPosition(pointerEvent);
} else {
this.onHide();
}
}
// Context menu actions
onSetTaskStarted(): void {
this.activity.progressRatio = 0.01;
this.gantt.redraw();
}
onSetActivityCompleted(): void {
this.activity.progressRatio = 1;
this.gantt.redraw();
}
onSetActivityLate(): void {
this.activity.deadline = 0;
this.activity.successorFinishesAfterDeadline = true;
this.gantt.redraw();
}
onSetActivityPriority(): void {
this.activity.isHighPriority = !this.activity.isHighPriority;
this.gantt.redraw();
}
} Concevons le onShow processus :
setOverlayElementPosition que nous avons créée dans notre classe abstraite et lui donner notre PointerEvent.onHide methode.Nos quatre actions mettront à jour les données d'activité et déclencheront un redraw, letting our underlying ActivityRenderer mettre à jour les graphiques avec ces nouvelles informations.
ScheduleJS propose un large éventail de méthodes événementielles que vous pouvez enregistrer dans l'objet principal : la méthode GanttChart. Une façon simple d'organiser le code est de créer un fichier GanttChart class that extends the default GanttChart.
// Here we create our custom GanttChart class
export class PlanningBoardGanttChart extends GanttChart<PlanningBoardRow> {
// Instantiate our PlanningBoardContextMenuOverlay class
readonly contextMenuOverlay: PlanningBoardContextMenuOverlay = new PlanningBoardContextMenuOverlay(this);
// The minimal GanttChart implementation requires the Angular injector
constructor(injector: Injector) {
super(undefined, injector);
}
// Event handlers [...]
} En tant que GanttChart est au cœur de ScheduleJS, sa classe est un endroit idéal pour enregistrer les moteurs de rendu par défaut, les couches du système et les gestionnaires d'événements. Notez que l'API ScheduleJS est accessible par l'intermédiaire de l'objet GanttChart avec des méthodes telles que gantt.getGraphics().
Le GanttChart propose un ensemble de méthodes surchargeables conçues pour gérer les données saisies par l'utilisateur sur les graphiques, par exemple :
onRowDrawingEnginePointerDownonDatelinePointerMoveonToggleGridCe que nous voulons faire ici, c'est remplacer la fonction onRowDrawingEngineContextMenu pour déclencher une logique lors de l'ouverture de notre menu contextuel. Dans un environnement de bureau, cette méthode est appelée lorsque l'utilisateur clique avec le bouton droit de la souris n'importe où sur les graphiques.
/**
* Trigger when right-clicking on the canvas
*/
onRowDrawingEngineContextMenu(pointerEvent: PointerEvent, row: PlanningBoardRow, index: number): void {
super.onRowDrawingEngineContextMenu(pointerEvent, row, index);
const hoveredActivity = this._getHoveredActivity();
if (hoveredActivity) {
this.tooltipOverlay.onHide();
this.contextMenuOverlay.onShow(pointerEvent, hoveredActivity);
this._changeDetectorRef.detectChanges();
}
} Maintenant, lorsque l'utilisateur clique avec le bouton droit de la souris sur les graphiques, ce code se déclenche avec l'événement de pointeur sous-jacent, la ligne actuelle et l'indice de ligne. Nous pouvons extraire la ligne courante hoveredActivity en utilisant le graphics.getHoveredActivity et la transmettre à la couche onShow methode.
Le menu contextuel que nous construisons ajoutera des interactions avec les activités présentes sur le canevas. Lors d'un clic droit de l'utilisateur, nous vérifions si nous survolons une activité, et si c'est le cas, nous masquons notre infobulle et déclenchons la commande contextMenuOverlay.onShow methode.
Pour des raisons de performance, cette méthode est exécutée en dehors de la zone Angular par ScheduleJS. Nous devons donc ajouter un appel à ChangeDetectorRef.detectChanges() pour déclencher manuellement la détection des changements et mettre à jour le DOM.
La vidéo suivante présente les quatre nouvelles actions que nous venons de créer :
Cet exemple n'est qu'une simple implémentation d'un menu contextuel, le but étant de vous donner des idées sur la façon dont vous pouvez interagir avec vos graphiques ScheduleJS. Vous pouvez utiliser les mêmes principes pour construire un menu contextuel plus avancé, ou même intégrer une bibliothèque tierce qui accélérera le développement du menu contextuel et déclenchera l'API ScheduleJS à partir d'ici. À vous de jouer !
ScheduleJS 1.4 release notes. A step forward towards modern Angular app building.
Angular 16 vs Angular 18 comparison: discover what's new in Angular, the arrival of signals, Zoneless mode, zone coalescing, and their impact on your projects.
Discover the Angular Rome Conference: workshops, domain-driven design, signals, state management, micro frontends.
Discover Angular 18: zoneless mode, zone coalescing, native await, and TypeScript 5.4 compatibility.
Le TOP 3 des diagrammes de Gantt JavaScript. Découvrez leurs caractéristiques, avantages et inconvénients pour choisir le meilleur outil pour votre projet.
Découvrez comment ScheduleJS s'est intégré en toute transparence à Selligent CRM, améliorant ainsi l'efficacité de la planification pour les consultants d'une grande marque de produits de beauté.
Cet article présente l'intégration d'un composant ScheduleJS dans un tableau Ag-Grid externe, afin de démontrer la flexibilité de ScheduleJS.
Comment synchroniser plusieurs graphiques ? Apprenez à réutiliser votre ligne de temps ScheduleJS dans plusieurs graphiques afin de les synchroniser.
Cet article montre comment mettre en œuvre un rendu dynamique en fonction du niveau de zoom actuel des graphiques.
Cet article propose une mise en œuvre pas à pas d'un mécanisme d'animation utilisant l'API JavaScript Date pour vos activités.