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

如何在Flutter Web中通过WebView使用D3.js或Chart.js展示图表?

在Flutter Web中使用D3.js绘制图表(含Dart向JS传数据)

webview_flutter包**仅针对移动端(iOS/Android)**提供WebView组件支持,Flutter Web本身运行在浏览器环境中,不需要额外的WebView,直接通过Dart与原生JS交互即可实现你的需求。以下是完整的实现方案:


步骤1:修改Web入口文件

在项目的web/index.html中引入D3.js的CDN,并编写绘制图表的JS函数:

<!DOCTYPE html>
<html>
<head>
  <!-- 其他原有代码 -->
  <script src="https://d3js.org/d3.v7.min.js"></script>
  <script>
    // 定义绘制柱状图的JS函数,接收Dart传递的数据
    function drawBarChart(data) {
      // 清空容器,避免重复绘制
      d3.select("#chart-container").selectAll("*").remove();

      // 图表基础配置
      const width = 400;
      const height = 300;
      const margin = {top: 20, right: 20, bottom: 30, left: 40};

      // 创建SVG容器
      const svg = d3.select("#chart-container")
        .append("svg")
        .attr("width", width)
        .attr("height", height);

      // X轴比例尺
      const x = d3.scaleBand()
        .domain(data.map(d => d.name))
        .range([margin.left, width - margin.right])
        .padding(0.1);

      // Y轴比例尺
      const y = d3.scaleLinear()
        .domain([0, d3.max(data, d => d.value)])
        .nice()
        .range([height - margin.bottom, margin.top]);

      // 添加X轴
      svg.append("g")
        .attr("transform", `translate(0,${height - margin.bottom})`)
        .call(d3.axisBottom(x));

      // 添加Y轴
      svg.append("g")
        .attr("transform", `translate(${margin.left},0)`)
        .call(d3.axisLeft(y));

      // 绘制柱状图
      svg.selectAll(".bar")
        .data(data)
        .join("rect")
        .attr("class", "bar")
        .attr("x", d => x(d.name))
        .attr("y", d => y(d.value))
        .attr("width", x.bandwidth())
        .attr("height", d => y(0) - y(d.value))
        .attr("fill", "steelblue");
    }
  </script>
</head>
<body>
  <!-- 其他原有代码 -->
</body>
</html>

步骤2:编写Flutter Dart代码

通过dart:js调用JS函数,并用HtmlElementView将图表嵌入Flutter Widget:

import 'dart:js' as js;
import 'dart:html' as html;
import 'package:flutter/material.dart';
import 'package:flutter_web_plugins/flutter_web_plugins.dart';

void main() {
  // 注册视图工厂,让HtmlElementView能找到对应的DOM元素
  registerViewFactory(
    "chart-container",
    (int viewId) => html.document.getElementById("chart-container")!,
  );
  runApp(const MyApp());
}

class MyApp extends StatelessWidget {
  const MyApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Flutter Web + D3.js',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const D3BarChart(),
    );
  }
}

class D3BarChart extends StatefulWidget {
  const D3BarChart({super.key});

  @override
  State<D3BarChart> createState() => _D3BarChartState();
}

class _D3BarChartState extends State<D3BarChart> {
  final String _chartId = "chart-container";

  @override
  void initState() {
    super.initState();
    // 创建图表容器DOM元素并添加到页面
    html.DivElement chartDiv = html.DivElement()
      ..id = _chartId
      ..style.width = "400px"
      ..style.height = "300px";
    html.document.body!.append(chartDiv);

    // 初始数据(从Dart传递到JS)
    final initialData = [
      {"name": "A", "value": 40},
      {"name": "B", "value": 60},
      {"name": "C", "value": 30},
      {"name": "D", "value": 70},
    ];
    // 调用JS函数绘制初始图表
    js.context.callMethod("drawBarChart", [initialData]);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(title: const Text("D3.js 柱状图示例")),
      body: Center(
        // 将DOM元素嵌入Flutter Widget
        child: HtmlElementView(viewType: _chartId),
      ),
      floatingActionButton: FloatingActionButton(
        onPressed: () {
          // 模拟更新数据,从Dart传递新数据到JS
          final newData = [
            {"name": "A", "value": 50},
            {"name": "B", "value": 35},
            {"name": "C", "value": 80},
            {"name": "D", "value": 45},
          ];
          js.context.callMethod("drawBarChart", [newData]);
        },
        child: const Icon(Icons.refresh),
      ),
    );
  }
}

核心说明

  1. 为什么不用webview_flutter?
    该包的设计目标是为移动端提供WebView容器,Flutter Web本身就在浏览器中运行,不需要额外嵌套WebView,直接操作原生JS即可。

  2. Dart与JS的数据传递
    Dart中的Map和List会自动转换为JS中的对象和数组,无需手动序列化/反序列化,直接传递即可。

  3. HtmlElementView的作用
    它是Flutter Web特有的Widget,用于将浏览器中的DOM元素嵌入Flutter的Widget树中,实现原生Web内容与Flutter界面的融合。

内容的提问来源于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:35:15