概述
在App Inventor 2中实现动态折线图/曲线图有两种主要方案:
| 方案 | 灵活度 | 性能 | 难度 |
|---|---|---|---|
| Chart组件(内置) | ⭐⭐ | 高 | ⭐ |
| ECharts + WebView | ⭐⭐⭐⭐⭐ | 中 | ⭐⭐⭐ |
方案一:内置Chart组件
组件位置
组件面板 → Charts → Chart + LineChart
基本使用
Chart组件需要配合数据源组件使用:
- ChartData — 静态数据
- FileData — 从文件读取数据
- WebData — 从网络API获取数据
- BluetoothData — 从蓝牙获取数据
添加Chart组件
- 在Designer中拖入 Chart 组件
- 设置Chart类型为 Line(折线图)
- 添加 ChartData 组件作为数据源
动态添加数据点
当 按钮_添加数据.被点击
设 值 = 文本转数字(输入框_数值.文本)
调用 ChartData1.添加数据项(值)
' 带标签的数据点
当 按钮_添加带标签.被点击
设 标签 = "第" & 数据计数 & "个"
设 值 = 文本转数字(输入框_数值.文本)
调用 ChartData1.添加数据项(标签, 值)
清除图表数据
当 按钮_清除.被点击
调用 ChartData1.清除数据()
实时更新图表(配合Clock)
设 数据计数 = 0
当 Screen1.初始化
设 Clock1.计时器间隔 = 1000 ' 每秒更新
设 Clock1.启用计时器 = true
当 Clock1.计时
设 数据计数 = 数据计数 + 1
设 随机值 = 数学.随机小数() * 100
调用 ChartData1.添加数据项("T" & 数据计数, 随机值)
' 限制显示最近20个点
如果 数据计数 > 20
调用 ChartData1.移除数据项(0)
Chart组件属性
| 属性 | 说明 |
|---|---|
| Type | 图表类型(Line/Bar/Scatter/Area) |
| Description | 图表描述 |
| LabelsFromX | 是否从X轴数据生成标签 |
| GridEnabled | 是否显示网格线 |
| LegendEnabled | 是否显示图例 |
| XFromZero | X轴是否从0开始 |
多条折线
添加多个ChartData组件,每个对应一条线:
当 Clock1.计时
设 值1 = 传感器值1
设 值2 = 传感器值2
调用 ChartData1.添加数据项(值1) ' 线1
调用 ChartData2.添加数据项(值2) ' 线2
方案二:ECharts + WebView
ECharts是百度开源的强大图表库,通过WebView可以在App Inventor中使用。
HTML文件(echarts_dynamic.html)
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<script src="https://cdn.jsdelivr.net/npm/echarts@5/dist/echarts.min.js"></script>
<style>
body { margin: 0; background: #fff; }
#chart { width: 100vw; height: 100vh; }
</style>
</head>
<body>
<div id="chart"></div>
<script>
var myChart = echarts.init(document.getElementById('chart'));
var data = [];
var labels = [];
var maxPoints = 30;
var option = {
title: { text: '实时数据监控', left: 'center', textStyle: { fontSize: 16 } },
tooltip: { trigger: 'axis' },
grid: { left: '10%', right: '5%', bottom: '15%', top: '20%' },
xAxis: { type: 'category', data: labels, axisLabel: { fontSize: 10 } },
yAxis: { type: 'value', axisLabel: { fontSize: 10 } },
series: [{
type: 'line',
data: data,
smooth: true,
lineStyle: { color: '#4CAF50', width: 2 },
areaStyle: { color: 'rgba(76,175,80,0.2)' },
itemStyle: { color: '#4CAF50' }
}],
dataZoom: [{ type: 'inside' }]
};
myChart.setOption(option);
setInterval(function() {
var msg = window.AppInventor.getWebViewString();
if (msg && msg !== "") {
try {
var parsed = JSON.parse(msg);
if (parsed.type === "add") {
data.push(parsed.value);
labels.push(parsed.label || "");
if (data.length > maxPoints) {
data.shift();
labels.shift();
}
myChart.setOption({ xAxis: { data: labels }, series: [{ data: data }] });
} else if (parsed.type === "multi") {
// 多条线
option.series = parsed.series;
option.xAxis.data = parsed.labels;
myChart.setOption(option, true);
} else if (parsed.type === "clear") {
data = [];
labels = [];
myChart.setOption({ xAxis: { data: [] }, series: [{ data: [] }] });
}
} catch(e) {}
window.AppInventor.setWebViewString("");
}
}, 100);
</script>
</body>
</html>
App Inventor积木块
设 数据计数 = 0
当 Screen1.初始化
设 WebView1.主页地址 = "file:///android_asset/echarts_dynamic.html"
设 Clock1.计时器间隔 = 500
设 Clock1.启用计时器 = true
当 Clock1.计时
设 数据计数 = 数据计数 + 1
设 值 = 数学.随机小数() * 100
设 消息 = "{""type"":""add"",""label"":""" & 数据计数 & """,""value"":" & 值 & "}"
设 WebView1.WebView字符串 = 消息
当 按钮_清除图表.被点击
设 WebView1.WebView字符串 = "{""type"":""clear""}"
设 数据计数 = 0
多条折线(ECharts)
当 按钮_显示多条线.被点击
设 JSON数据 = "{
""type"":""multi"",
""labels"":[""1月"",""2月"",""3月"",""4月"",""5月""],
""series"":[
{""type"":""line"",""name"":""温度"",""data"":[5,8,15,22,28],""smooth"":true},
{""type"":""line"",""name"":""湿度"",""data"":[80,70,60,55,50],""smooth"":true}
]
}"
设 WebView1.WebView字符串 = JSON数据
实战案例:温度监测折线图
功能需求
- 每2秒采集一次温度(模拟)
- 实时更新折线图
- 显示最高/最低/平均温度
- 可以暂停/继续
积木块代码
设 温度列表 = 创建空列表
设 时间列表 = 创建空列表
设 是否运行 = false
设 采集计数 = 0
当 Screen1.初始化
设 WebView1.主页地址 = "file:///android_asset/echarts_dynamic.html"
当 按钮_开始.被点击
设 是否运行 = true
设 Clock1.计时器间隔 = 2000
设 Clock1.启用计时器 = true
设 按钮_开始.文本 = "暂停"
当 Clock1.计时
如果 是否运行
设 采集计数 = 采集计数 + 1
' 模拟温度数据(20-30度随机波动)
设 温度 = 25 + (数学.随机小数() - 0.5) * 10
设 温度 = 数学.保留小数(温度, 1)
设 时间标签 = Clock1.格式化日期时间(Clock1.当前时间(), "HH:mm:ss")
设 温度列表 = 添加列表项(温度列表, 温度)
设 时间列表 = 添加列表项(时间列表, 时间标签)
' 更新图表
设 消息 = "{""type"":""add"",""label"":""" & 时间标签 & """,""value"":" & 温度 & "}"
设 WebView1.WebView字符串 = 消息
' 更新统计
设 最高 = 列表最大值(温度列表)
设 最低 = 列表最小值(温度列表)
设 平均 = 列表求和(温度列表) / 列表长度(温度列表)
标签_统计.文本 = "最高:" & 最高 & "°C | 最低:" & 最低 & "°C | 平均:" & 数学.保留小数(平均, 1) & "°C"
常见问题
Q1: Chart组件数据多了会卡顿?
内置Chart组件在100+数据点时可能变慢。解决方案:
- 定期清除旧数据
- 使用ECharts方案(性能更好)
- 限制显示的数据点数量
Q2: ECharts图表在WebView中显示不全?
确保HTML中容器尺寸正确:
#chart { width: 100vw; height: 100vh; }
WebView的宽高也需要正确设置。
Q3: 如何实现饼图/柱状图?
ECharts方案中修改series的type:
- 折线图:
type: 'line' - 柱状图:
type: 'bar' - 饼图:
type: 'pie' - 散点图:
type: 'scatter'
Q4: 图表可以导出为图片吗?
ECharts支持导出图片:
var imgData = myChart.getDataURL({ type: 'png' });
window.AppInventor.setWebViewString("IMG:" + imgData);
总结
| 需求 | 推荐方案 |
|---|---|
| 简单折线图 | 内置Chart组件 |
| 实时动态图 | ECharts + WebView |
| 多种图表类型 | ECharts |
| 自定义样式 | ECharts |
| 离线使用 | 内置Chart组件 |
版权声明:MIT App Inventor 官方文档采用 CC BY-SA 4.0 授权,本文档由 ai2claw 🐝 整理。
扫码添加客服咨询