The TOP 3 JavaScript Gantt chart. Discover their features, advantages, and disadvantages to choose the best tool for your project.
ScheduleJS uses the HTML Canvas rendering engine to draw the grid, activities, additional layers and links. This article explains how to design a simple ScheduleJS rendering animation using the HTML Canvas API
Have you ever been using the Canvas technology before? The canvas element is an HTML container used to draw programmatically using JavaScript at a surprisingly low cost for the browser.
The most significant feature of the canvas element is that its possibilities are endless in terms of design and interactions. The only limit to what’s on the screen is our imagination.
If you want to wrap your head around the canvas element, you can compare it to a blank drawing paper.
According to the MDN web documentation:
MDN: The Canvas API provides a means for drawing graphics via JavaScript and the HTML canvas element. Among other things, it can be used for animation, game graphics, data visualization, photo manipulation, and real-time video processing.
The Canvas API largely focuses on 2D graphics. The WebGL API, which also uses the canvas element, draws hardware-accelerated 2D and 3D graphics.
Once you draw your activities on the canvas, the only way to get it to change is to clean it up and start drawing again.
Under the hood, ScheduleJS implements multiple tools to handle this behavior in the context of a scheduling application. These APIs are sometimes exposed to the developer and sometimes they work silently to let the developer focus on the core features of the application, like the following:
The most significant item for the developer in this architecture is the ScheduleJS Renderer API. Renderers use overridable functions allowing the developer to create his or her unique way of drawing specific parts of the application:
Although this may seem complicated to some people, it is a workflow that developers will get used to quickly. The flexibility of the Renderer architecture and its well-thought implementation allows endless design and interaction scenarios.
To animate your Canvas, you have to break down your animation in frames and tell the renderer how to draw each frame. The main ingredient required to create a simple linear animation is the time at which the animation started. If we want to animate every activity on its own, a good place to store this information is the activity data structure.
// A simple activity class storing the animation start date as a timestamp
export class MyActivity extends MutableActivityBase {
animationStart: number = undefined;
}
Let’s create a simple animated renderer to draw every frame based on animation progression. This simple width animation will animate our activity on creation (from 0% width to full-width).
// Create our activity renderer for our simple animation
export class MyActivityRenderer extends ActivityBarRenderer<MyActivity, Row> {
// Our animation takes 250ms
private _animationDurationMs: number = 250;
// Override the drawActivity method of the ActivityBarRenderer
protected drawActivity(activityRef: ActivityRef<Action>, position: ViewPosition, ctx: CanvasRenderingContext2D, x: number, y: number, w: number, h: number, selected: boolean, hover: boolean, highlighted: boolean, pressed: boolean): ActivityBounds {
// What time is it? :)
const now = Date.now();
// Access your activity in the renderer
const activity = activityRef.getActivity();
// Set animationStart timestamp
if (activity.animationStart === undefined) {
activity.animationStart = now;
}
// The animationTimer tells us the current frame
const animationTimer = now - activity.animationStart;
// Calculate the sequence: 0 = animation starts, 1 = animation ends
const sequence = animationTimer / this._newActionAnimationDurationMs;
// Let's play with the width: starts at 0%, ends at 100%
w *= sequence > 1 ? 1 : sequence;
// Note: Calling directly graphics.redraw() will cause an infinite loop
requestAnimationFrame(() => {
// Force a redraw on every animation frame
this.getGraphics().redraw();
// Our custom drawing method
this.drawMyActivity(activity, x, y, w, h, selected, hover, highlighted, pressed);
});
return new ActivityBounds(activityRef, x, y, w, h);
}
This example focuses on the code required to run the animation. As you can see, we created a ratio (from 0 to 1) describing the duration of our animation and we simply multiply the width by this ratio. As a result, the activity width will expand in a smooth 250ms animation (see below).
The TOP 3 JavaScript Gantt chart. Discover their features, advantages, and disadvantages to choose the best tool for your project.
Discover how ScheduleJS seamlessly integrated with Selligent CRM, enhancing scheduling efficiency for a leading beauty brand's consultants.
This article showcases the integration of a ScheduleJS component into an external Ag-Grid table, to demonstrate the flexibility of ScheduleJS.
How to synchronize multiple graphics? Learn how to reuse your ScheduleJS timeline in multiple graphics to keep them synchronized.
How to build an interactive context menu? A deep dive into ScheduleJS event handling and recommended practice to build your own context menu.
This article shows how to implement dynamic rendering depending on the current zoom-level of the graphics.
This article will cover a websocket implementation featuring real time data rendering using the ScheduleJS drawing engine.
This article will go through the implementation of a custom info column using an AG Grid component in place of the default one.
This article will show you how the parent-child tree Gantt architecture within the ScheduleJS Viewer was built.
This article will showcase how the main activity renderer of the ScheduleJS Viewer was built with code examples.