"Si un trabajador quiere hacer bien su trabajo, primero debe afilar sus herramientas." - Confucio, "Las Analectas de Confucio. Lu Linggong"
Página delantera > Programación > Construyendo un ActivityRenderer

Construyendo un ActivityRenderer

Publicado el 2024-08-05
Navegar:482

El procesador de actividades de Gantt es el procesador principal de ScheduleJS Viewer. Este artículo analizará cómo está construido y cuáles son las especificidades de este renderizador de actividades.

Cómo construir una clase de renderizador personalizada

El primer paso para construir una clase de renderizador es heredar atributos y métodos extendiendo una clase marco de orden superior.

Queremos representar las tareas solo a través de sus dimensiones de tiempo de inicio y finalización. La clase de renderizador base de ScheduleJS para hacer esto es la clase ActivityBarRenderer.

Necesitamos proporcionar argumentos de tipo personalizado a la clase ActivityBarRenderer para que los atributos y métodos proporcionados por nuestras clases personalizadas Row y Activity sean accesibles. usando la API de clase base.

Creemos la clase ScheduleJsViewerTaskActivityRenderer para dibujar cada ScheduleJsViewerTaskActivity en su respectiva 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 { }

Tal como está, el renderizador ya se puede registrar para dibujar nuestras actividades usando el comportamiento predeterminado de ActivityBarRenderer. Ahora profundicemos en cómo personalizarlo.

La arquitectura base

En ScheduleJS, un ActivityRenderer es una clase que registramos mediante programación usando la API de gráficos para dibujar una Actividad específica en su Fila. Para organizar nuestro ScheduleJsViewerTaskActivityRenderer, separaremos su código en tres secciones:

  • Los atributos contendrán variables que nos permitirán cambiar el comportamiento de un procedimiento de dibujo específico.
  • El constructor nos permitirá definir un estado predeterminado para el renderizador.
  • Los métodos de dibujo contendrán todas las instrucciones para dibujar nuestras actividades en el lienzo.

Atributos

Los atributos son constantes que se reutilizarán en todo el renderizador. Tal como están, estas propiedades solo se editarán directamente en el código del renderizador. Podemos imaginar una pantalla específica donde el usuario podría modificar estas configuraciones directamente en la 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;

Constructor

El constructor está estrechamente acoplado a nuestro método de ciclo de vida del renderizador. En ScheduleJS Viewer, decidimos crear una instancia del renderizador cada vez que el usuario cambia de pantalla para definir especificidades y reutilizar nuestro código en cada pestaña que implemente este renderizador. Significa que la función constructora se ejecuta cada vez que el usuario selecciona una pantalla que presenta este renderizador.

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

}

setFill, setStroke, setFillHover, setStrokeHover, setLineWidth y setBarHeight se heredan y se utilizan para alterar las características de representación predeterminadas de la clase ActivityBarRenderer.

Las características predeterminadas de este renderizador son las siguientes:

  • Un color personalizado al pasar el cursor sobre las actividades
  • Un trazo de línea negra (para bordes de actividad)
  • Un grosor de línea de trazo de 0,5 píxeles
  • Una barra de actividad con una altura de 8 píxeles
  • Un color de relleno condicional: Azul para niños y marrón para padres en la pestaña WBS Verde para niños y gris para padres en las otras pestañas

Dibujo

El marco llamará automáticamente al método drawActivity para representar nuestras actividades en el lienzo. Todos sus parámetros se completan dinámicamente, lo que le permite reaccionar en tiempo real al estado actual de sus actividades.

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

El sorteo se realizará de esta manera:

  • Obtenga información sobre la Actividad y la Fila actuales usando la ActivityRef API
  • Establece colores dinámicamente usando nuestro método _setActivityColor
  • Dibuja texto de actividad usando nuestro método _drawActivityText
  • Dibuja la actividad en sí usando dos métodos: El método _drawParentActivity para dibujar padres El método ActivityBarRenderer predeterminado de super.drawActivity para dibujar niños

Métodos de dibujo de actividades personalizados

Echemos un vistazo más de cerca a cómo dibujar libremente su actividad diseñando sus propios métodos con el método _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);
  }

Aquí utilizamos directamente la HTMLCanvas API para definir nuestra estrategia de dibujo configurando CanvasRenderingContex2D. La única operación relacionada con el marco realizada en este método es crear algunos ActivityBounds nuevos para la Activity principal actual.

El marco crea un mapa usando ActivityBounds debajo del capó para registrar todas las actividades en la pantalla. Este mapa ayuda al desarrollador al proporcionar una lógica similar a un elemento para crear experiencias de usuario avanzadas basadas en información precisa y, al mismo tiempo, aprovechar el rendimiento de la HTMLCanvas API.

Los métodos de dibujo de elementos como _drawParentActivityStartTriangle dependen de la API CanvasRenderingContext2D para dibujar a nivel de píxel.

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

Resultado final

Para registrar su nuevo renderizador, utilice el método Graphics.setActivityRenderer:

// Register the renderer

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

brand-new renderer

Para ver el vídeo del resultado final puedes ir a ver: Construyendo un ActivityRenderer

Declaración de liberación Este artículo se reproduce en: https://dev.to/lenormor/building-an-activityrenderer-3o0?1 Si hay alguna infracción, comuníquese con [email protected] para eliminarla.
Último tutorial Más>

Descargo de responsabilidad: Todos los recursos proporcionados provienen en parte de Internet. Si existe alguna infracción de sus derechos de autor u otros derechos e intereses, explique los motivos detallados y proporcione pruebas de los derechos de autor o derechos e intereses y luego envíelos al correo electrónico: [email protected]. Lo manejaremos por usted lo antes posible.

Copyright© 2022 湘ICP备2022001581号-3