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

参考资料

相关推荐
艾德金的溪1 分钟前
windows安装CC Switch
运维·ai
kyle~5 分钟前
推理部署---CUDA 执行模型(SM、Block、Warp 与 SIMT)
人工智能·nvidia·cuda
淮南颂恩少儿编程C++6 分钟前
在淮南:编程信息学培训与 C++ 信奥赛:从 CSP 到 NOI 的进阶之路
人工智能·学习·青少年编程
甲维斯6 分钟前
真不想吹Claude Fable了,奈何实力不允许!
人工智能·ai编程·游戏开发
想要成为计算机高手7 分钟前
用meta quest 3 遥操宇树机器人-xr_teleoperate 复现(含docker安装与配置方式)
人工智能·docker·机器人·xr·g1·具身智能
aqi007 分钟前
15天学会AI应用开发(六)使用离线大模型对文本生成摘要
人工智能·python·ai编程
qq_411262429 分钟前
AI-02模组架构与Coze智能体接入说明
人工智能·ai·架构·esp32-c3·coze·四博
果丁智能12 分钟前
民宿/网约房数字化升级:基于智能锁的身份核验与远程授权解决方案
人工智能·智能家居
知识浅谈15 分钟前
人工智能日报 每日AI新闻(2026年6月12日):Agent安全、AI编程与国内高考场景加速落地
人工智能·安全·ai编程
麦哲思科技任甲林18 分钟前
让AI帮我们写工作日志
人工智能·ai编程·日志