OpenClaw Canvas:可视化界面入门

目录

    • 摘要
    • [1. 引言 - 为什么需要 Canvas?](#1. 引言 - 为什么需要 Canvas?)
      • [1.1 Canvas 的价值](#1.1 Canvas 的价值)
      • [1.2 Canvas 架构](#1.2 Canvas 架构)
      • [1.3 Canvas 能力概览](#1.3 Canvas 能力概览)
    • [2. Canvas 基础操作](#2. Canvas 基础操作)
      • [2.1 展示界面 (present)](#2.1 展示界面 (present))
      • [2.2 导航页面 (navigate)](#2.2 导航页面 (navigate))
      • [2.3 执行脚本 (eval)](#2.3 执行脚本 (eval))
      • [2.4 截图 (snapshot)](#2.4 截图 (snapshot))
    • [3. 展示 HTML 内容](#3. 展示 HTML 内容)
      • [3.1 基本用法](#3.1 基本用法)
      • [3.2 带样式的界面](#3.2 带样式的界面)
      • [3.3 响应式设计](#3.3 响应式设计)
    • [4. 展示外部网页](#4. 展示外部网页)
      • [4.1 基本用法](#4.1 基本用法)
      • [4.2 设置尺寸](#4.2 设置尺寸)
      • [4.3 嵌入文档](#4.3 嵌入文档)
    • [5. 实战案例一:数据仪表盘](#5. 实战案例一:数据仪表盘)
      • [5.1 场景描述](#5.1 场景描述)
      • [5.2 实现代码](#5.2 实现代码)
    • [6. 实战案例二:交互式表单](#6. 实战案例二:交互式表单)
      • [6.1 场景描述](#6.1 场景描述)
      • [6.2 实现代码](#6.2 实现代码)
    • [7. 实战案例三:报告展示](#7. 实战案例三:报告展示)
      • [7.1 场景描述](#7.1 场景描述)
      • [7.2 实现代码](#7.2 实现代码)
    • [8. 高级功能](#8. 高级功能)
      • [8.1 执行 JavaScript](#8.1 执行 JavaScript)
      • [8.2 获取截图](#8.2 获取截图)
      • [8.3 A2UI 交互](#8.3 A2UI 交互)
    • [9. 最佳实践](#9. 最佳实践)
      • [9.1 设计原则](#9.1 设计原则)
      • [9.2 常见问题](#9.2 常见问题)
    • [10. 总结](#10. 总结)
      • [10.1 核心要点](#10.1 核心要点)
      • [10.2 下一步](#10.2 下一步)
    • 参考资料

摘要

本文介绍 OpenClaw 框架中的 Canvas 可视化界面功能。从 Canvas 基本概念、核心操作、界面展示到实际应用,全面解析如何通过 AI Agent 创建和管理可视化界面。通过实际案例演示网页嵌入、自定义界面、交互式应用等场景,帮助开发者构建具有可视化能力的智能应用。🎨


1. 引言 - 为什么需要 Canvas?

1.1 Canvas 的价值

场景 说明 示例
可视化展示 展示图表、报告 数据仪表盘
交互界面 提供用户交互 配置面板
网页嵌入 嵌入外部网页 文档、工具
实时预览 实时展示结果 代码预览

1.2 Canvas 架构

OpenClaw Canvas
AI Agent
Canvas Tool
操作类型
present - 展示界面
navigate - 导航URL
eval - 执行JS
snapshot - 截图
渲染界面
获取截图

1.3 Canvas 能力概览

能力 说明 Action
展示界面 展示 HTML/URL present
导航页面 加载指定 URL navigate
执行脚本 运行 JavaScript eval
截图 捕获界面图像 snapshot
A2UI 交互式界面 a2ui_push

2. Canvas 基础操作

2.1 展示界面 (present)

python 复制代码
canvas(
    action="present",
    url="https://example.com"  # 或使用 html 参数
)

2.2 导航页面 (navigate)

python 复制代码
canvas(
    action="navigate",
    url="https://example.com"
)

2.3 执行脚本 (eval)

python 复制代码
canvas(
    action="eval",
    javaScript="document.title"
)

2.4 截图 (snapshot)

python 复制代码
canvas(
    action="snapshot",
    outputFormat="png"  # 或 "jpg"
)

3. 展示 HTML 内容

3.1 基本用法

python 复制代码
canvas(
    action="present",
    html="""
    <!DOCTYPE html>
    <html>
    <head>
        <title>Hello Canvas</title>
    </head>
    <body>
        <h1>Hello, OpenClaw Canvas!</h1>
        <p>这是一个简单的 HTML 页面</p>
    </body>
    </html>
    """
)

3.2 带样式的界面

python 复制代码
canvas(
    action="present",
    html="""
    <!DOCTYPE html>
    <html>
    <head>
        <style>
            body {
                font-family: Arial, sans-serif;
                padding: 20px;
                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                color: white;
            }
            .card {
                background: rgba(255,255,255,0.1);
                padding: 20px;
                border-radius: 10px;
                backdrop-filter: blur(10px);
            }
            h1 { margin: 0; }
        </style>
    </head>
    <body>
        <div class="card">
            <h1>📊 数据仪表盘</h1>
            <p>实时数据展示</p>
        </div>
    </body>
    </html>
    """
)

3.3 响应式设计

python 复制代码
canvas(
    action="present",
    html="""
    <!DOCTYPE html>
    <html>
    <head>
        <meta name="viewport" content="width=device-width, initial-scale=1.0">
        <style>
            .container {
                display: grid;
                grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
                gap: 20px;
                padding: 20px;
            }
            .item {
                background: #f5f5f5;
                padding: 20px;
                border-radius: 8px;
                text-align: center;
            }
        </style>
    </head>
    <body>
        <div class="container">
            <div class="item">项目 1</div>
            <div class="item">项目 2</div>
            <div class="item">项目 3</div>
            <div class="item">项目 4</div>
        </div>
    </body>
    </html>
    """
)

4. 展示外部网页

4.1 基本用法

python 复制代码
canvas(
    action="present",
    url="https://docs.openclaw.ai"
)

4.2 设置尺寸

python 复制代码
canvas(
    action="present",
    url="https://example.com",
    width=800,
    height=600
)

4.3 嵌入文档

python 复制代码
def show_documentation():
    """展示 OpenClaw 文档"""
    canvas(
        action="present",
        url="https://docs.openclaw.ai",
        width=1000,
        height=700
    )

5. 实战案例一:数据仪表盘

5.1 场景描述

创建一个实时数据展示仪表盘。

5.2 实现代码

python 复制代码
def show_dashboard(data):
    """展示数据仪表盘"""
    html = f"""
    <!DOCTYPE html>
    <html>
    <head>
        <title>数据仪表盘</title>
        <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
        <style>
            body {{
                font-family: 'Segoe UI', Arial, sans-serif;
                background: #1a1a2e;
                color: white;
                padding: 20px;
                margin: 0;
            }}
            .header {{
                text-align: center;
                margin-bottom: 30px;
            }}
            .stats {{
                display: grid;
                grid-template-columns: repeat(4, 1fr);
                gap: 20px;
                margin-bottom: 30px;
            }}
            .stat-card {{
                background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
                padding: 20px;
                border-radius: 10px;
                text-align: center;
            }}
            .stat-value {{
                font-size: 2em;
                font-weight: bold;
            }}
            .stat-label {{
                opacity: 0.8;
            }}
            .chart-container {{
                background: #16213e;
                padding: 20px;
                border-radius: 10px;
            }}
        </style>
    </head>
    <body>
        <div class="header">
            <h1>📊 实时数据仪表盘</h1>
            <p>数据更新时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}</p>
        </div>
        
        <div class="stats">
            <div class="stat-card">
                <div class="stat-value">{data['total_users']}</div>
                <div class="stat-label">总用户数</div>
            </div>
            <div class="stat-card">
                <div class="stat-value">{data['active_users']}</div>
                <div class="stat-label">活跃用户</div>
            </div>
            <div class="stat-card">
                <div class="stat-value">{data['requests']}</div>
                <div class="stat-label">请求数</div>
            </div>
            <div class="stat-card">
                <div class="stat-value">{data['success_rate']}%</div>
                <div class="stat-label">成功率</div>
            </div>
        </div>
        
        <div class="chart-container">
            <canvas id="chart"></canvas>
        </div>
        
        <script>
            const ctx = document.getElementById('chart').getContext('2d');
            new Chart(ctx, {{
                type: 'line',
                data: {{
                    labels: {data['labels']},
                    datasets: [{{
                        label: '请求数',
                        data: {data['values']},
                        borderColor: '#667eea',
                        backgroundColor: 'rgba(102, 126, 234, 0.1)',
                        fill: true
                    }}]
                }},
                options: {{
                    responsive: true,
                    plugins: {{
                        legend: {{
                            labels: {{ color: 'white' }}
                        }}
                    }},
                    scales: {{
                        y: {{
                            ticks: {{ color: 'white' }},
                            grid: {{ color: 'rgba(255,255,255,0.1)' }}
                        }},
                        x: {{
                            ticks: {{ color: 'white' }},
                            grid: {{ color: 'rgba(255,255,255,0.1)' }}
                        }}
                    }}
                }}
            }});
        </script>
    </body>
    </html>
    """
    
    canvas(action="present", html=html)

6. 实战案例二:交互式表单

6.1 场景描述

创建一个可交互的配置表单。

6.2 实现代码

python 复制代码
def show_config_form():
    """展示配置表单"""
    html = """
    <!DOCTYPE html>
    <html>
    <head>
        <title>配置面板</title>
        <style>
            body {
                font-family: Arial, sans-serif;
                background: #f5f5f5;
                padding: 20px;
            }
            .form-container {
                max-width: 500px;
                margin: 0 auto;
                background: white;
                padding: 30px;
                border-radius: 10px;
                box-shadow: 0 2px 10px rgba(0,0,0,0.1);
            }
            h2 {
                margin-top: 0;
                color: #333;
            }
            .form-group {
                margin-bottom: 20px;
            }
            label {
                display: block;
                margin-bottom: 5px;
                font-weight: bold;
                color: #555;
            }
            input, select {
                width: 100%;
                padding: 10px;
                border: 1px solid #ddd;
                border-radius: 5px;
                box-sizing: border-box;
            }
            .btn {
                background: #667eea;
                color: white;
                border: none;
                padding: 12px 24px;
                border-radius: 5px;
                cursor: pointer;
                font-size: 16px;
            }
            .btn:hover {
                background: #5a6fd6;
            }
        </style>
    </head>
    <body>
        <div class="form-container">
            <h2>⚙️ 配置面板</h2>
            
            <div class="form-group">
                <label>模型选择</label>
                <select id="model">
                    <option value="gpt-4">GPT-4</option>
                    <option value="gpt-3.5-turbo">GPT-3.5 Turbo</option>
                    <option value="claude-3">Claude 3</option>
                </select>
            </div>
            
            <div class="form-group">
                <label>温度参数</label>
                <input type="number" id="temperature" value="0.7" min="0" max="2" step="0.1">
            </div>
            
            <div class="form-group">
                <label>最大Token数</label>
                <input type="number" id="max_tokens" value="2000" min="100" max="8000">
            </div>
            
            <button class="btn" onclick="submitConfig()">保存配置</button>
        </div>
        
        <script>
            function submitConfig() {
                const config = {
                    model: document.getElementById('model').value,
                    temperature: parseFloat(document.getElementById('temperature').value),
                    max_tokens: parseInt(document.getElementById('max_tokens').value)
                };
                console.log('配置已保存:', config);
                alert('配置已保存!');
            }
        </script>
    </body>
    </html>
    """
    
    canvas(action="present", html=html)

7. 实战案例三:报告展示

7.1 场景描述

展示格式化的报告内容。

7.2 实现代码

python 复制代码
def show_report(title, content, stats):
    """展示报告"""
    html = f"""
    <!DOCTYPE html>
    <html>
    <head>
        <title>{title}</title>
        <style>
            body {{
                font-family: 'Georgia', serif;
                max-width: 800px;
                margin: 0 auto;
                padding: 40px;
                background: #fafafa;
            }}
            .report {{
                background: white;
                padding: 40px;
                border-radius: 10px;
                box-shadow: 0 2px 20px rgba(0,0,0,0.1);
            }}
            h1 {{
                color: #333;
                border-bottom: 3px solid #667eea;
                padding-bottom: 10px;
            }}
            .meta {{
                color: #888;
                font-size: 0.9em;
                margin-bottom: 30px;
            }}
            .content {{
                line-height: 1.8;
                color: #444;
            }}
            .stats-box {{
                background: #f8f9fa;
                padding: 20px;
                border-radius: 8px;
                margin: 20px 0;
            }}
            .stats-box h3 {{
                margin-top: 0;
                color: #667eea;
            }}
            .stat-item {{
                display: flex;
                justify-content: space-between;
                padding: 10px 0;
                border-bottom: 1px solid #eee;
            }}
        </style>
    </head>
    <body>
        <div class="report">
            <h1>{title}</h1>
            <div class="meta">
                生成时间: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}
            </div>
            
            <div class="content">
                {content}
            </div>
            
            <div class="stats-box">
                <h3>📊 统计数据</h3>
                <div class="stat-item">
                    <span>总字数</span>
                    <span>{stats['words']}</span>
                </div>
                <div class="stat-item">
                    <span>段落数</span>
                    <span>{stats['paragraphs']}</span>
                </div>
                <div class="stat-item">
                    <span>预计阅读时间</span>
                    <span>{stats['read_time']} 分钟</span>
                </div>
            </div>
        </div>
    </body>
    </html>
    """
    
    canvas(action="present", html=html)

8. 高级功能

8.1 执行 JavaScript

python 复制代码
def update_canvas_data(data):
    """更新 Canvas 中的数据"""
    canvas(
        action="eval",
        javaScript=f"""
        document.getElementById('data-display').textContent = '{data}';
        """
    )

8.2 获取截图

python 复制代码
def capture_canvas():
    """截取 Canvas 内容"""
    screenshot = canvas(
        action="snapshot",
        outputFormat="png"
    )
    return screenshot

8.3 A2UI 交互

python 复制代码
def push_interactive_ui():
    """推送交互式界面"""
    canvas(
        action="a2ui_push",
        jsonl="""
        {"type": "text", "content": "Hello"}
        {"type": "button", "label": "Click me", "action": "click"}
        """
    )

9. 最佳实践

9.1 设计原则

原则 说明
简洁清晰 界面简洁,信息清晰
响应式 适配不同尺寸
性能优化 避免过多资源
用户体验 良好的交互反馈

9.2 常见问题

问题 解决方案
加载慢 减少外部资源
样式错乱 使用内联样式
交互失效 检查JS代码
截图空白 等待加载完成

10. 总结

10.1 核心要点

要点 说明
HTML展示 使用 present + html 参数
URL展示 使用 present + url 参数
脚本执行 使用 eval 执行 JS
截图获取 使用 snapshot 获取图像

10.2 下一步

  • 第52篇:OpenClaw Canvas 导航:URL 加载与控制
  • 第53篇:OpenClaw Canvas 执行:JavaScript 注入实战

参考资料

相关推荐
回眸&啤酒鸭2 天前
【回眸】Minicart 电商购物车核心功能落地指南
人工智能
一隅论数智2 天前
给AI一张“业务概念地图“:本体如何从哲学走向企业智能
大数据·人工智能·经验分享·笔记·学习·学习方法·政务
AI的探索之旅2 天前
97 个 OpenCV 实例(三十):双目立体,从标定到点云
人工智能·opencv·计算机视觉
AlbertZein2 天前
Step-5-Preview 上手实测:3D 游戏、金融分析、网页设计一次跑完
人工智能·aigc
LaughingZhu2 天前
Product Hunt 每日热榜 | 2026-09-19
人工智能·深度学习·神经网络·搜索引擎·百度
美狐美颜SDK开放平台2 天前
开发直播APP时如何接入视频美颜SDK?开发流程与注意事项
android·人工智能·计算机视觉·音视频·直播美颜sdk
wukangjupingbb2 天前
智能网联汽车安全能力框架
人工智能
感谢地心引力2 天前
我用 Doubao-Seed-2.1-pro 做了一个深度融入 AI 功能的本地知识库软件
ai·开源·seed·markdown·豆包
龙亘川2 天前
明月照湾区,智启新赛道:从顶流文旅IP盛会看智慧文旅升级路径
人工智能·智慧城市·开源软件·数据可视化