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 注入实战

参考资料

相关推荐
霸道流氓气质4 小时前
普通办公电脑基于 Ollama 的本地 AI 能力技术文档
人工智能·电脑
点云-激光雷达-Slam-三维牙齿4 小时前
速度起飞 笔记本电脑6G显卡llama运行Qwen3.6 35BA3B MTP 大模型
人工智能·python·电脑·llama
Shockang10 小时前
AI 智能体安全沙盒实战
人工智能
yuhulkjv33510 小时前
Claude表格复制到word不再崩溃,AI导出鸭批量导出+格式无损一键搞定
人工智能·ai·c#·word·ai导出鸭
大明者省12 小时前
WSL2 Ubuntu22.04 GPU训练环境配置指南
人工智能·算法·计算机视觉
抱抱宝12 小时前
Agent-study项目教程(03):手写 Mini-ReAct Agent(不依赖框架)
javascript·人工智能·gpt·react.js·prompt·agent
抱抱宝12 小时前
大模型应用开发教程08 | 构建完整 RAG 应用(Chroma/FAISS 实战)
人工智能·gpt·prompt·agent
美团技术团队12 小时前
KDD‘26 美团学术论文精选及KDD Cup‘26 DataAgents赛道冠军思路解读
人工智能
AKAMAI12 小时前
当AI模型超出存储增长时
人工智能·云计算
科技绘图13 小时前
快鲸GEO vs 传统AI搜索优化:全链路自动化与高效内容生产在转化闭环上的对比
数据库·人工智能·自动化