"Si un ouvrier veut bien faire son travail, il doit d'abord affûter ses outils." - Confucius, "Les Entretiens de Confucius. Lu Linggong"
Page de garde > La programmation > Construire un moteur de rendu d'activité

Construire un moteur de rendu d'activité

Publié le 2024-08-05
Parcourir:298

Le moteur de rendu d'activité Gantt est le moteur de rendu principal de la visionneuse ScheduleJS. Cet article expliquera comment il est construit et quelles sont les spécificités de ce moteur de rendu d'activité.

Comment créer une classe de rendu personnalisée

La première étape pour créer une classe de rendu consiste à hériter des attributs et des méthodes en étendant une classe de structure d'ordre supérieur.

Nous souhaitons représenter les tâches uniquement à travers leurs dimensions d'heure de début et de fin. La classe de rendu de base ScheduleJS pour ce faire est la classe ActivityBarRenderer.

Nous devons fournir les arguments de type personnalisé à la classe ActivityBarRenderer afin que les attributs et méthodes fournis par nos classes personnalisées Row et Activity soient accessibles en utilisant l'API de classe de base.

Créons la classe ScheduleJsViewerTaskActivityRenderer pour dessiner chaque ScheduleJsViewerTaskActivity dans leur ScheduleJsViewerTaskRow.

// Import the base ActivityBarRenderer class from ScheduleJS
import {ActivityBarRenderer} from "schedule";

// Import our custom Activity and Row types
import {ScheduleJsViewerTaskActivity} from "...";
import {ScheduleJsViewerTaskRow} from "...";

// Create our custom renderer by extending the ActivityBarRenderer class
export class ScheduleJsViewerTaskActivityRenderer extends ActivityBarRenderer { }

En l'état, le moteur de rendu peut déjà être enregistré pour dessiner nos activités en utilisant le comportement par défaut de ActivityBarRenderer. Voyons maintenant comment le personnaliser.

L'architecture de base

Dans ScheduleJS, un ActivityRenderer est une classe que nous enregistrons par programme à l'aide de l'API graphique pour dessiner une Activité spécifique sur sa Row. Pour organiser notre ScheduleJsViewerTaskActivityRenderer, nous allons séparer son code en trois sections :

  • Les attributs contiendront des variables qui nous permettront de modifier le comportement d'une procédure de dessin spécifique.
  • Le constructeur va nous laisser définir un état par défaut pour le moteur de rendu.
  • Les méthodes de dessin contiendront toutes les instructions pour dessiner nos activités sur la toile.

Les attributs

Les attributs sont des constantes qui seront réutilisées dans tout le moteur de rendu. En l'état, ces propriétés ne seront modifiées que directement dans le code du moteur de rendu. On peut imaginer un écran spécifique où l'utilisateur pourrait modifier ces paramètres directement dans l'UI.

// Attributes

// Pixels sizings
private readonly _parentActivityTrianglesWidthPx: number = 5;
private readonly _parentActivityTrianglesHeightPx: number = 8;
private readonly _defaultLineWidthPx: number = 0.5;

// Colors palette
private readonly _parentActivityColor: string = Color.GRAY.toCssString();
private readonly _strokeColor: string = Color.BLACK.toCssString();
private readonly _defaultActivityGreen: Color = Color.rgb(28, 187, 158);
private readonly _defaultActivityBlue: Color = Color.rgb(53, 152, 214);
private readonly _onHoverFillColor: string = Color.ORANGE.toCssString();

// Opacity ratio for baseline activities
private readonly _baselineOpacityRatio: number = 0.6;

Constructeur

Le constructeur est étroitement couplé à notre méthode de cycle de vie du moteur de rendu. Dans le ScheduleJS Viewer, nous avons décidé d'instancier le moteur de rendu à chaque fois que l'utilisateur change d'écran pour définir les spécificités et réutiliser notre code dans chaque onglet qui implémente ce moteur de rendu. Cela signifie que la fonction constructeur est exécutée chaque fois que l'utilisateur sélectionne un écran présentant ce moteur de rendu.

// Constructor

// The renderer requires the graphics and the current tab variable
constructor(graphics: GraphicsBase,
            private _currentRibbonMenuTab: ScheduleJsViewerRibbonMenuTabsEnum) {

  // The ActivityBarRenderer class requires the graphics and a name for the renderer
  super(graphics, ScheduleJsViewerRenderingConstants.taskActivityRendererName);

  // Default fill color when hovering an activity
  this.setFillHover(Color.web(this._onHoverFillColor));

  // Default stroke color when hovering an activity
  this.setStrokeHover(Color.BLACK);

  // Default stroke color
  this.setStroke(Color.BLACK);

  // Default thickness
  this.setLineWidth(this._defaultLineWidthPx);

  // Default bar height
  this.setBarHeight(8);

  // Default fill color based on current tab 
  switch (_currentRibbonMenuTab) {
    // Change color for the WBS tab
    case ScheduleJsViewerRibbonMenuTabsEnum.WBS:
      this._parentActivityColor = ScheduleJsViewerColors.brown;
      this.setFill(this._defaultActivityBlue);
      break;
    default:
      this._parentActivityColor = Color.GRAY.toCssString();
      this.setFill(this._defaultActivityGreen);
      break;
  }

}

Les éléments setFill, setStroke, setFillHover, setStrokeHover, setLineWidth et setBarHeight sont hérités et utilisés pour modifier les caractéristiques de rendu par défaut de la classe ActivityBarRenderer.

Les fonctionnalités par défaut de ce moteur de rendu sont les suivantes :

  • Une couleur personnalisée lors du survol des activités
  • Un trait de ligne noire (pour les bordures d'activité)
  • Une épaisseur de trait de 0,5 pixel
  • Une barre d'activité d'une hauteur de 8 pixels
  • Une couleur de remplissage conditionnelle : Bleu pour les enfants et marron pour les parents dans l'onglet WBS Vert pour les enfants et gris pour les parents dans les autres onglets

Dessin

Le framework appellera automatiquement la méthode drawActivity pour restituer nos activités sur le canevas. Tous ses paramètres sont renseignés dynamiquement, vous permettant de réagir en temps réel à l'état actuel de vos activités.

// Main drawing method

drawActivity(activityRef: ActivityRef,
             position: ViewPosition,
             ctx: CanvasRenderingContext2D,
             x: number,
             y: number,
             w: number,
             h: number,
             selected: boolean,    
             hover: boolean,
             highlighted: boolean,
             pressed: boolean     
            ): ActivityBounds {    // This method has to return ActivityBounds

    // True if current activity includes a comparison task
    const hasModifications = !!activityRef.getActivity().diffTask;

    // True if current row has children
    const isParent = activityRef.getRow().getChildren().length;

    // Set colors dynamically
    this._setActivityColor(activityRef, hasModifications);

    // Draw text
    this._drawActivityText(activityRef, ctx, x, y, w, h, hasModifications);

    // Run a custom method to draw parent activities or delegate to the default method
    return isParent
      ? this._drawParentActivity(activityRef, ctx, x, y, w, h, hover, hasModifications)
      : super.drawActivity(activityRef, position, ctx, x, y, w, h, selected, hover, highlighted, pressed);
  }

Le dessin se déroulera de cette façon :

  • Obtenez des informations sur l'Activity et la Row actuelles à l'aide de l'API ActivityRef
  • Définissez les couleurs de manière dynamique à l'aide de notre méthode _setActivityColor
  • Dessinez le texte de l'activité à l'aide de notre méthode _drawActivityText
  • Dessinez l'activité elle-même en utilisant deux méthodes : La méthode _drawParentActivity pour dessiner les parents La méthode ActivityBarRenderer par défaut de super.drawActivity pour dessiner des enfants

Méthodes de dessin d'activités personnalisées

Regardons de plus près comment dessiner librement votre activité en concevant vos propres méthodes avec la méthode _drawParentActivity.

// Draw the parent activity

private _drawParentActivity(activityRef: ActivityRef,
                            ctx: CanvasRenderingContext2D,
                            x: number,
                            y: number,
                            w: number,
                            h: number,
                            hover: boolean,
                            hasModifications: boolean
                           ): ActivityBounds {

    // Set padding
    const topPadding = h / 3.5;
    const leftPadding = 1;

    // Set CanvasRenderingContext2D
    ctx.lineWidth = this._defaultLineWidthPx;
    if (hover) {
      ctx.fillStyle = this._onHoverFillColor;
      ctx.strokeStyle = ScheduleJsViewerColors.brown;
    } else if (hasModifications) {
      ctx.fillStyle = Color.web(this._parentActivityColor).withOpacity(this._baselineOpacityRatio).toCssString();
      ctx.strokeStyle = `rgba(0,0,0,${this._baselineOpacityRatio})`;
    } else {
      ctx.fillStyle = this._parentActivityColor;
      ctx.strokeStyle = this._strokeColor;
    }

    // Draw elements
    ScheduleJsViewerTaskActivityRenderer._drawParentActivityStartTriangle(ctx, x   leftPadding, y   topPadding, this._parentActivityTrianglesWidthPx, this._parentActivityTrianglesHeightPx);
    ScheduleJsViewerTaskActivityRenderer._drawParentActivityBody(ctx, x   leftPadding, y   topPadding, w, this._parentActivityTrianglesWidthPx, this._parentActivityTrianglesHeightPx);
    ScheduleJsViewerTaskActivityRenderer._drawParentActivityEndTriangle(ctx, x   leftPadding, y   topPadding, w, this._parentActivityTrianglesWidthPx, this._parentActivityTrianglesHeightPx);

    // Return positions to update where your activity should be responsive
    return new ActivityBounds(activityRef, x, y, w, h);
  }

Ici, nous utilisons directement l'API HTMLCanvas pour définir notre stratégie de dessin en configurant le CanvasRenderingContex2D. La seule opération liée au framework effectuée dans cette méthode consiste à créer de nouveaux ActivityBounds pour le parent actuel Activity.

Le framework crée une carte en utilisant ActivityBounds sous le capot pour enregistrer toutes les activités à l'écran. Cette carte aide le développeur en fournissant une logique de type élément pour créer des expériences utilisateur avancées basées sur des informations précises tout en tirant parti des performances de l'API HTMLCanvas.

Les méthodes de dessin d'éléments telles que _drawParentActivityStartTriangle s'appuient sur l'API CanvasRenderingContext2D pour dessiner au niveau du pixel.

// Draw the start triangle element of the parent activity

private static _drawParentActivityStartTriangle(ctx: CanvasRenderingContext2D,
                                                x: number,
                                                y: number,
                                                triangleWidth: number,
                                                triangleHeight: number): void {
    ctx.beginPath();
    ctx.moveTo(x, y);
    ctx.lineTo(x , y   triangleHeight);
    ctx.lineTo(x   triangleWidth, y);
    ctx.lineTo(x, y);
    ctx.fill();
    ctx.stroke();
    ctx.closePath();
}

Résultat final

Pour enregistrer votre tout nouveau moteur de rendu, utilisez la méthode graphiques.setActivityRenderer :

// Register the renderer

graphics.setActivityRenderer(ScheduleJsViewerTaskActivity, GanttLayout, new ScheduleJsViewerTaskActivityRenderer(graphics, currentRibbonMenuTab));

brand-new renderer

Pour voir la vidéo du résultat final vous pouvez aller voir : Construire un ActivityRenderer

Déclaration de sortie Cet article est reproduit sur : https://dev.to/lenormor/building-an-activityrenderer-3o0?1 En cas de violation, veuillez contacter [email protected] pour le supprimer.
Dernier tutoriel Plus>

Clause de non-responsabilité: Toutes les ressources fournies proviennent en partie d'Internet. En cas de violation de vos droits d'auteur ou d'autres droits et intérêts, veuillez expliquer les raisons détaillées et fournir une preuve du droit d'auteur ou des droits et intérêts, puis l'envoyer à l'adresse e-mail : [email protected]. Nous nous en occuperons pour vous dans les plus brefs délais.

Copyright© 2022 湘ICP备2022001581号-3