How We Brought ChartSpace to Flutter Using a Cross‑Platform Canvas
This article explains how a graphics‑grammar‑based chart library called ChartSpace was ported to Flutter by recording Web canvas commands in a mock canvas, replaying them on Flutter's canvas, handling touch interaction conversion, and optimizing performance, while sharing the challenges and solutions encountered.
Background
ChartSpace is a chart library built on the grammar of graphics, originally supporting Web, H5, and mini‑programs. The business required the same library to run on Flutter, preserving consistent visual output across platforms.
Grammar of Graphics
The grammar of graphics describes any visual by a set of declarative parameters, allowing the same data to be rendered as a bar chart, rose chart, or pie chart simply by changing the configuration. This approach offers great flexibility but introduces a more complex syntax.
ChartSpace Library
ChartSpace uses JSON configuration to define chart semantics. Existing front‑end libraries based on this concept include G2 (Ant Financial), Vega, and ChartSpace itself.
Solution Overview
Instead of re‑implementing the entire library in Dart, we adopted a cross‑platform canvas approach: the JavaScript version of ChartSpace draws on a Web canvas, we record those canvas commands, and then replay them on Flutter's canvas.
Drawing the Canvas
The core idea is to create a mock Canvas object in JavaScript that captures drawing instructions. These instructions are sent to the Flutter side, where a custom Flutter canvas implementation executes them, effectively mirroring the Web canvas API.
class WebCanvas {
SaveStack saveStack = SaveStack();
SaveInfo get current => saveStack.current;
...
}We also built a CanvasRecorder to manage the lifecycle of the mock canvas and keep its state consistent with the Web canvas.
class CanvasRecorder {
CanvasHistory getCanvasHistory(String canvasId) {
if (!hisMap.containsKey(canvasId)) {
hisMap.putIfAbsent(canvasId, () => CanvasHistory(canvasId));
}
return hisMap[canvasId];
}
...
}Handling Interaction
User input on Flutter arrives as PointerEvent. We translate these to Web TouchEvent objects and feed them back into ChartSpace, which then emits new canvas commands that are replayed on the Flutter canvas, completing the interaction loop.
Performance Results
After integration, the rendering performance was measured:
Cross‑platform canvas graph rendering: 52 ms
Pure Flutter implementation: 20 ms
Tooltip rendering (cross‑platform): 9 ms
Tooltip rendering (pure Flutter): 0 ms
Although the cross‑platform approach is slower than a native Flutter implementation, the difference is acceptable for typical user interactions.
Pitfalls & Solutions
Canvas Lifecycle Differences
Flutter canvas instances are recreated on each paint, while Web canvas retains state. We solved this by persisting the rendered picture and drawing on top of it in subsequent frames.
@override
void paint(Canvas canvas, Size size) {
final paintList = _repaint.consume();
ui.Picture picture = canvasRecorder.record(canvasId, size, _repaint.reverse, paintList);
if (picture != null) {
canvas.drawPicture(picture);
}
}Canvas Context Mismatches
Methods like save / restore behave differently. We introduced a WebCanvas wrapper that manually tracks the save stack to emulate Web behavior.
Default Value Differences
Transform matrices differ between the two platforms. We provided a utility to generate a Web‑compatible default matrix:
class Matrix4Builder {
static Matrix4 webDefault() {
final matrix4 = Matrix4.zero();
matrix4.setEntry(0, 0, 1.0);
matrix4.setEntry(1, 1, 1.0);
matrix4.setEntry(2, 2, 1.0);
matrix4.setEntry(3, 3, 1.0);
return matrix4;
}
}Summary & Future Work
By leveraging a cross‑platform canvas, we achieved a low‑cost Flutter implementation of ChartSpace with acceptable performance. The JSON‑based grammar of graphics proved valuable for multi‑platform consistency, though it incurs higher computational overhead compared to fixed‑type charts.
Future directions include:
Designing a higher‑level API that abstracts the complex grammar for easier usage.
Extending support to additional platforms such as iOS native, Android native, and React Native.
Open‑sourcing the Flutter implementation after further internal validation.
References
[1] https://zhuanlan.zhihu.com/p/47550015
[2] https://segmentfault.com/a/1190000041004457
[3] https://zhuanlan.zhihu.com/p/339275513
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
ByteDance Terminal Technology
Official account of ByteDance Terminal Technology, sharing technical insights and team updates.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
