You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

能否在Flutter中使用Chart.js、D3.js等JS可视化库?如何实现?

在Flutter中使用Chart.js/D3.js等JS可视化库的方案

是否可行?

完全可行,主要有两种主流实现方式:通过WebView加载包含JS可视化库的HTML页面,或是借助flutter_js这类JS引擎桥接包结合自定义交互逻辑实现。

具体实现方式

方式一:WebView加载HTML页面(推荐用于复杂可视化)

这是最直接的方案,因为Chart.js、D3.js本身就是为Web环境设计的,WebView能提供完整的DOM和Canvas支持:

  1. 编写本地HTML文件,引入Chart.js/D3.js的CDN或本地脚本,编写可视化逻辑。比如一个简单的Chart.js示例:
<!-- assets/charts.html -->
<!DOCTYPE html>
<html>
<head>
  <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
</head>
<body>
  <canvas id="myChart" width="400" height="400"></canvas>
  <script>
    // 接收Flutter传递的数据
    window.addEventListener('message', (event) => {
      const ctx = document.getElementById('myChart').getContext('2d');
      new Chart(ctx, {
        type: 'bar',
        data: event.data
      });
    });
  </script>
</body>
</html>
  1. 在Flutter中使用webview_flutter包加载该HTML文件,并通过JS通道传递数据:
import 'package:flutter/material.dart';
import 'package:webview_flutter/webview_flutter.dart';

class ChartWebView extends StatefulWidget {
  @override
  State<ChartWebView> createState() => _ChartWebViewState();
}

class _ChartWebViewState extends State<ChartWebView> {
  late WebViewController controller;

  @override
  void initState() {
    super.initState();
    controller = WebViewController()
      ..loadFlutterAsset('assets/charts.html')
      ..addJavaScriptChannel('FlutterChart', onMessageReceived: (message) {
        // 接收JS的回调信息
        print(message.message);
      });
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: WebViewWidget(controller: controller),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // 向JS传递图表数据
          final chartData = {
            'labels': ['Red', 'Blue', 'Yellow'],
            'datasets': [{
              'label': 'Votes',
              'data': [12, 19, 3],
              'backgroundColor': ['#ff0000', '#0000ff', '#ffff00']
            }]
          };
          controller.runJavaScript("window.postMessage(${chartData})");
        },
        child: Icon(Icons.refresh),
      ),
    );
  }
}

方式二:使用flutter_js包(适合轻量场景)

flutter_js能在Flutter中运行JS代码,但它本身没有DOM环境,直接使用Chart.js/D3.js会报错,需额外处理:

  1. 引入flutter_js依赖到pubspec.yaml:
dependencies:
  flutter_js: ^0.7.0
  1. 通过JS与Flutter的通信,将绘图指令传递给Flutter的Canvas(需手动桥接逻辑):
import 'package:flutter/material.dart';
import 'package:flutter_js/flutter_js.dart';

class JsChartPage extends StatefulWidget {
  @override
  State<JsChartPage> createState() => _JsChartPageState();
}

class _JsChartPageState extends State<JsChartPage> {
  late JavascriptRuntime jsRuntime;
  final CanvasController _canvasController = CanvasController();

  @override
  void initState() {
    super.initState();
    jsRuntime = getJavascriptRuntime();
    // 向JS注册Flutter的Canvas操作方法
    jsRuntime.onMessage('drawRect', (args) {
      _canvasController.drawRect(
        double.parse(args[0]),
        double.parse(args[1]),
        double.parse(args[2]),
        double.parse(args[3]),
        args[4],
      );
    });

    // 执行JS绘图逻辑
    jsRuntime.evaluate("""
      window.drawRect = (x, y, w, h, color) => {
        sendMessage('drawRect', [x, y, w, h, color]);
      };
      // 调用Flutter Canvas绘制矩形
      drawRect(10, 10, 100, 50, '#ff0000');
    """);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      body: CustomPaint(
        painter: ChartPainter(_canvasController),
        size: Size.infinite,
      ),
    );
  }
}

// 自定义Canvas绘制器
class ChartPainter extends CustomPainter {
  final CanvasController controller;
  ChartPainter(this.controller) : super(repaint: controller);

  @override
  void paint(Canvas canvas, Size size) {
    controller.canvas = canvas;
    controller.executeDraws();
  }

  @override
  bool shouldRepaint(covariant CustomPainter oldDelegate) => true;
}

class CanvasController extends ChangeNotifier {
  late Canvas canvas;
  final List<Function> _drawTasks = [];

  void drawRect(double x, double y, double width, double height, String color) {
    _drawTasks.add(() {
      final paint = Paint()..color = Color(int.parse(color.replaceFirst('#', '0xFF')));
      canvas.drawRect(Rect.fromLTWH(x, y, width, height), paint);
    });
    notifyListeners();
  }

  void executeDraws() {
    for (final task in _drawTasks) {
      task();
    }
  }
}

这种方式开发成本较高,仅适合简单自定义绘图,复杂可视化优先选择WebView方案。

是否可以通过JS访问Flutter的Canvas?

JS无法直接访问Flutter原生Canvas,但可以通过Flutter与JS的通信通道实现间接交互:

  • 若用WebView:JS只能操作WebView内部的Web Canvas,可通过JS通道将绘图数据传给Flutter,由Flutter在原生Canvas上绘制。
  • 若用flutter_js:可以向JS暴露Flutter的Canvas操作API,让JS调用这些API间接控制原生Canvas,如上述示例所示。

内容的提问来源于stack exchange,提问作者psygo

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 18:20:28