Customizing Chart Shapes
Relevant source files
The following files were used as context for generating this wiki page:
- frontend/src/klinechart/src/Chart.js
- frontend/src/klinechart/types/Chart.d.ts
- frontend/src/klinechart/tests/shape-template.html
- frontend/src/klinechart/tests/shape-override.html
- frontend/src/pages/chart/graphicMarks.ts
- frontend/src/klinechart/src/view/TechnicalIndicatorOverlayView.js
- frontend/src/pages/chart/index.tsx
The KLineChart system provides a robust framework for creating and customizing "Shapes," which are graphical overlays used for technical analysis, measurement, and drawing tools. Shapes are built using a template-driven architecture that allows developers to define custom interaction logic, data processing, and rendering behaviors on top of the chart's canvas.
Custom shapes can be applied to any pane within the chart, including the main candlestick pane or sub-panes used for indicators. This system supports multi-step drawing processes (e.g., clicking two points to create a line) and provides event hooks for user interactions like clicking, hovering, and moving.
Sources: frontend/src/klinechart/src/Chart.js:356-405, frontend/src/pages/chart/index.tsx:106-120
Shape Architecture and Lifecycle
The shape system operates through a central shapeStore managed by the main Chart instance. The lifecycle of a shape involves registration via a template, instantiation through a creation call, and continuous rendering via the overlay view.
The Template System
Before a shape can be created, its definition must be registered as a template. A template defines the identity and behavioral rules for the shape.
The diagram shows the transition from a static template definition to an active rendered instance.
Sources: frontend/src/klinechart/src/Chart.js:356-384, frontend/src/klinechart/src/view/TechnicalIndicatorOverlayView.js:84-93
Key Components of a Template
A shape template requires several properties and methods to function within the chart's event loop:
| Property | Type | Description |
|---|---|---|
name | string | Unique identifier for the shape type. |
totalStep | number | Number of interaction steps (clicks) required to complete the drawing. |
checkEventCoordinateOnShape | function | Logic to determine if a mouse coordinate "hits" the shape for interaction. |
createShapeDataSource | function | Transforms coordinates/points into internal drawing data structures. |
drawExtend | function | Optional hook for custom canvas rendering using the CanvasRenderingContext2D. |
Sources: frontend/src/klinechart/tests/shape-template.html:39-66, frontend/src/pages/chart/graphicMarks.ts:4-152
Defining Interaction Logic
Shapes are highly interactive. The totalStep property dictates the drawing flow. For example, a "circle" might require 2 steps: one for the center and one for the radius.
Coordinate Validation
The checkEventCoordinateOnShape method is crucial for event handling (hover, click, drag). It typically involves geometric calculations to see if the user's mouse is near the shape's data points or segments.
This sequence illustrates how the chart determines interaction hits based on template logic.
Sources: frontend/src/klinechart/tests/shape-template.html:42-47, frontend/src/pages/chart/graphicMarks.ts:7-13
Custom Rendering with drawExtend
While standard shapes use a data-driven approach via createShapeDataSource, complex tools (like the "Measure" tool) use drawExtend to access the raw HTML5 Canvas API.
// Example from a measurement tool implementation
drawExtend: ({ ctx, dataSource }) => {
const polygonDataSource = dataSource?.[1]?.dataSource;
ctx.fillStyle = "rgba(33,150,243,0.1)";
ctx.fillRect(
polygonDataSource[0][0].x,
polygonDataSource[0][0].y,
width,
height
);
// ... additional custom drawing logic
}
Sources: frontend/src/pages/chart/graphicMarks.ts:80-151
API Methods for Shape Management
The Chart class provides several methods for programmatically managing shapes and their properties.
| Method | Parameters | Description |
|---|---|---|
addShapeTemplate | template | template[] | Registers one or more new shape definitions. |
createShape | value, paneId | Instantiates a shape. value can be a name or a config object. |
getShape | shapeId | Retrieves information about a specific shape instance. |
setShapeOptions | options | Updates an existing shape (e.g., locking it or changing styles). |
removeShape | shapeId | Deletes a shape instance from the chart. |
Sources: frontend/src/klinechart/src/Chart.js:356-405, frontend/src/klinechart/types/Chart.d.ts:57-61
Overriding and Styles
Shape instances can be customized after creation using setShapeOptions. This allows for dynamic behavior such as locking a shape to prevent movement or changing colors based on state.
// Overriding an existing shape instance
chart.setShapeOptions({
id: 'shape_123',
lock: true,
styles: {
arc: { style: 'fill', fill: { color: 'rgba(10, 230, 100, .3)' } }
}
});
Sources: frontend/src/klinechart/tests/shape-override.html:62-67, frontend/src/klinechart/src/Chart.js:392-398
Integration in Application Logic
In a production environment, shapes are often synchronized with a backend. The application handles drawing events to persist shape coordinates.
- Creation: The user selects a tool (e.g., "Segment").
- Drawing:
onDrawEndis triggered oncetotalStepis reached. - Persistence: The application calls an API to save the coordinates.
- Update:
onPressedMovetriggers debounced updates to the database when the user drags shape points.
Sources: frontend/src/pages/chart/index.tsx:183-210, frontend/src/pages/chart/index.tsx:288-320
The shape system's flexibility allows KLineChart to support everything from simple lines to complex financial measurement tools by abstracting canvas complexity into manageable templates.
Summary: Customizing chart shapes in this repository involves registering templates that define interaction steps, hit-testing, and rendering logic, which are then instantiated and managed via the Chart API.