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.
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 :
onRowDrawingEnginePointerDown
onDatelinePointerMove
onToggleGrid
Ce 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 !
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.
Cet article traite d'une implémentation de websocket avec un rendu de données en temps réel en utilisant le moteur de dessin ScheduleJS.
Cet article présente l'implémentation d'une colonne d'information personnalisée en utilisant un composant AG Grid à la place du composant par défaut.
Cet article vous montrera comment a été construite l'architecture de l'arbre de Gantt parent-enfant dans le ScheduleJS Viewer.
Cet article montre comment le moteur de rendu de l'activité principale du ScheduleJS Viewer a été construit à l'aide d'exemples de code.