Maison  >  Article  >  interface Web  >  Construire un moteur de rendu d'activité

Construire un moteur de rendu d'activité

王林
王林original
2024-07-16 21:19:14905parcourir

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 framework d'ordre supérieur.

Nous souhaitons représenter les tâches uniquement à travers leurs dimensions temporelles 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 la 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<ScheduleJsViewerTaskActivity, ScheduleJsViewerTaskRow> { }

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 nous laissera 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.

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<ScheduleJsViewerTaskRow>,
            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 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<ScheduleJsViewerTaskActivity>,
             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 tirage 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<ScheduleJsViewerTaskActivity>,
                            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 mettant en place 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.

The draw elements methods like _drawParentActivityStartTriangle rely on the CanvasRenderingContext2D API to draw at the pixel level.

// 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();
}

Final result

To register your brand-new renderer, use the graphics.setActivityRenderer method:

// Register the renderer

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

brand-new renderer

To see the video of the final result you can go to see: Building an ActivityRenderer

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn