"Se um trabalhador quiser fazer bem o seu trabalho, ele deve primeiro afiar suas ferramentas." - Confúcio, "Os Analectos de Confúcio. Lu Linggong"
Primeira página > Programação > Construindo um ActivityRenderer

Construindo um ActivityRenderer

Publicado em 2024-08-05
Navegar:948

O renderizador de atividades Gantt é o renderizador principal do ScheduleJS Viewer. Este artigo irá discutir como ele é construído e quais são as especificidades deste renderizador de atividades.

Como construir uma classe de renderizador personalizada

A primeira etapa para construir uma classe renderizadora é herdar atributos e métodos estendendo uma classe de estrutura de ordem superior.

Queremos representar tarefas apenas por meio de suas dimensões de horário de início e término. A classe renderizadora base do ScheduleJS para fazer isso é a classe ActivityBarRenderer.

Precisamos fornecer os argumentos de tipo personalizado para a classe ActivityBarRenderer para que os atributos e métodos fornecidos por nossas classes personalizadas Row e Activity sejam acessíveis usando a API da classe base.

Vamos criar a classe ScheduleJsViewerTaskActivityRenderer para desenhar cada ScheduleJsViewerTaskActivity em seus respectivos 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 { }

No estado em que se encontra, o renderizador já pode ser registrado para desenhar nossas atividades usando o comportamento padrão do ActivityBarRenderer. Agora vamos ver como personalizá-lo.

A arquitetura básica

No ScheduleJS, um ActivityRenderer é uma classe que registramos programaticamente usando a API Graphics para desenhar uma Activity específica em sua Row. Para organizar nosso ScheduleJsViewerTaskActivityRenderer, vamos separar seu código em três seções:

  • Os atributos conterão variáveis ​​que nos permitem alterar o comportamento de um procedimento de desenho específico.
  • O construtor nos permitirá definir um estado padrão para o renderizador.
  • Os métodos de desenho conterão todas as instruções para desenhar nossas atividades na tela.

Atributos

Atributos são constantes que serão reutilizadas em todo o renderizador. No estado em que se encontram, essas propriedades só serão editadas diretamente no código do renderizador. Podemos imaginar uma tela específica onde o usuário poderia modificar essas configurações diretamente na 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;

Construtor

O construtor está fortemente acoplado ao nosso método de ciclo de vida do renderizador. No ScheduleJS Viewer, decidimos instanciar o renderizador sempre que o usuário troca de tela para definir especificidades e reaproveitar nosso código em todas as abas que implementam esse renderizador. Isso significa que a função construtora é executada toda vez que o usuário seleciona uma tela com 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 e setBarHeight são herdados e usados ​​para alterar as características de renderização padrão da classe ActivityBarRenderer.

Os recursos padrão deste renderizador são os seguintes:

  • Uma cor personalizada ao passar o mouse sobre as atividades
  • Um traço de linha preta (para bordas de atividades)
  • Uma espessura de linha de traço de 0,5 pixels
  • Uma barra de atividades com altura de 8 pixels
  • Uma cor de preenchimento condicional: Azul para crianças e marrom para pais na guia EAP Verde para crianças e cinza para pais nas outras abas

Desenho

A estrutura chamará automaticamente o método drawActivity para renderizar nossas atividades na tela. Todos os seus parâmetros são preenchidos dinamicamente, permitindo reagir em tempo real ao estado atual de suas atividades.

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

O sorteio ocorrerá desta forma:

  • Obtenha informações sobre a Activity e a Row atuais usando a ActivityRef API
  • Defina cores dinamicamente usando nosso método _setActivityColor
  • Desenhe o texto da atividade usando nosso método _drawActivityText
  • Desenhe a própria atividade com base em dois métodos: O método _drawParentActivity para desenhar pais O método ActivityBarRenderer padrão super.drawActivity para desenhar filhos

Métodos personalizados de desenho de atividades

Vamos dar uma olhada mais de perto em como desenhar livremente sua atividade, projetando seus próprios métodos com o 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);
  }

Aqui usamos diretamente a HTMLCanvas API para definir nossa estratégia de desenho configurando o CanvasRenderingContex2D. A única operação relacionada à estrutura feita neste método é criar alguns novos ActivityBounds para o pai atual Activity.

A estrutura cria um mapa usando ActivityBounds nos bastidores para registrar todas as atividades na tela. Este mapa ajuda o desenvolvedor fornecendo uma lógica semelhante a um elemento para criar experiências de usuário avançadas com base em informações precisas e, ao mesmo tempo, aproveitar o desempenho da API HTMLCanvas.

Os métodos de elementos de desenho, como _drawParentActivityStartTriangle, dependem da API CanvasRenderingContext2D para desenhar no nível do 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();
}

Resultado final

Para registrar seu novo renderizador, use o método graphics.setActivityRenderer:

// Register the renderer

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

brand-new renderer

Para ver o vídeo do resultado final você pode acessar: Construindo um ActivityRenderer

Declaração de lançamento Este artigo foi reproduzido em: https://dev.to/lenormor/building-an-activityrenderer-3o0?1 Se houver alguma violação, entre em contato com [email protected] para excluí-lo
Tutorial mais recente Mais>

Isenção de responsabilidade: Todos os recursos fornecidos são parcialmente provenientes da Internet. Se houver qualquer violação de seus direitos autorais ou outros direitos e interesses, explique os motivos detalhados e forneça prova de direitos autorais ou direitos e interesses e envie-a para o e-mail: [email protected]. Nós cuidaremos disso para você o mais rápido possível.

Copyright© 2022 湘ICP备2022001581号-3