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

参考资料

相关推荐
lili00121 小时前
Gemini 3.5发布后的AI格局:谷歌重新定义行业标准
java·人工智能·python·ai编程
柒星栈1 小时前
Agentic AI深度解读:从架构到开源实战,一次讲清!
人工智能·开源
小康小小涵1 小时前
基于ROS-Noetic的Gmapping等四种SLAM建图方法与Dijkstra等两种导航算法的实验与分析
人工智能·机器人·自动驾驶
收放扳机1 小时前
蜘蛛机械手高速收板方案:CD视觉与并联机械手的技术特点
人工智能·科技·自动化·制造·pcb工艺
@蔓蔓喜欢你1 小时前
WebSocket 实战:构建实时通信应用
人工智能·ai
小黄人软件1 小时前
AI时代什么是高价值目标?
大数据·人工智能
gjhave1 小时前
jetson agx xaviar刷机过程
人工智能
GIOTTO情1 小时前
Infoseek 危机公关自动化闭环系统,实现 PR 运维工程化
人工智能·算法·机器学习
南屹川1 小时前
【架构设计】微服务架构设计模式:从单体到分布式的演进之路
人工智能