Просмотр исходного кода

docs: update plugin development docs to v1.2

- Added plot APIs: Symja.plot(), parametricPlot(), listPlot()
- Expanded API table with 30+ methods (calculus, algebra, matrix,
  number theory, numeric, LaTeX, plotting, trigonometry)
- Added plot plugin example
- Updated feature list: Canvas rendering, MCP server, image save
- Updated rules section

Co-Authored-By: Claude <noreply@anthropic.com>
nonvioce 3 месяцев назад
Родитель
Сommit
258851887a

+ 69 - 62
app/src/main/assets/console.html

@@ -122,8 +122,8 @@
         <!-- 开发文档 -->
         <div class="plugin-docs tab-content" data-content="docs">
             <div class="doc-section">
-                <h3>📖 插件开发指南 (v1.1)</h3>
-                
+                <h3>📖 插件开发指南 (v1.2)</h3>
+
                 <h4>基本结构</h4>
                 <div class="code-block">{
   "id": "circle_area",
@@ -140,9 +140,19 @@
   "jsCode": "function calculate(inputs, Symja) {\n  Symja.print('计算圆面积');\n  return `Pi*${inputs.radius}^2`;\n}"
 }</div>
             </div>
-            
+
+            <div class="doc-section">
+                <h4>🎉 v1.2 新功能</h4>
+                <ul>
+                    <li><strong>🎨 Canvas 绘图</strong> — <code>Symja.plot()</code> 函数图像、<code>Symja.parametricPlot()</code> 参数方程、<code>Symja.listPlot()</code> 散点图</li>
+                    <li><strong>🌐 MCP 服务器</strong> — 支持远程调用插件,结果实时同步到控制台</li>
+                    <li><strong>💾 图片保存</strong> — 绘图结果可保存到相册</li>
+                    <li><strong>📦 14个默认插件</strong> — 统计、概率、几何、数列工具开箱即用</li>
+                </ul>
+            </div>
+
             <div class="doc-section">
-                <h4>🎉 v1.1 核心特性</h4>
+                <h4>v1.1 特性</h4>
                 <ul>
                     <li><strong>输入自动转换</strong> - 用户输入自动转换为 Symja 可运算类型</li>
                     <li><strong>Symja.print()</strong> - 输出说明文本,不影响返回值</li>
@@ -178,66 +188,45 @@
             <div class="doc-section">
                 <h4>常用 API</h4>
                 <table class="api-table">
-                    <tr>
-                        <th>分类</th>
-                        <th>方法</th>
-                    </tr>
-                    <tr>
-                        <td>输入输出</td>
-                        <td><code>Symja.print(msg)</code></td>
-                    </tr>
-                    <tr>
-                        <td>基础</td>
-                        <td><code>Symja.eval(expr)</code></td>
-                    </tr>
-                    <tr>
-                        <td>微积分</td>
-                        <td><code>differentiate(expr, var)</code></td>
-                    </tr>
-                    <tr>
-                        <td></td>
-                        <td><code>integrate(expr, var)</code></td>
-                    </tr>
-                    <tr>
-                        <td>代数</td>
-                        <td><code>solve(eq, var)</code></td>
-                    </tr>
-                    <tr>
-                        <td></td>
-                        <td><code>simplify(expr)</code></td>
-                    </tr>
-                    <tr>
-                        <td></td>
-                        <td><code>expand(expr)</code></td>
-                    </tr>
-                    <tr>
-                        <td></td>
-                        <td><code>factor(expr)</code></td>
-                    </tr>
-                    <tr>
-                        <td>矩阵</td>
-                        <td><code>matrix.det(m)</code></td>
-                    </tr>
-                    <tr>
-                        <td></td>
-                        <td><code>matrix.inverse(m)</code></td>
-                    </tr>
-                    <tr>
-                        <td>数论</td>
-                        <td><code>gcd(a, b)</code></td>
-                    </tr>
-                    <tr>
-                        <td>数值</td>
-                        <td><code>numeric(expr, prec)</code></td>
-                    </tr>
+                    <tr><th>分类</th><th>方法</th></tr>
+                    <tr><td>输入输出</td><td><code>Symja.print(msg)</code></td></tr>
+                    <tr><td>基础计算</td><td><code>Symja.eval(expr)</code></td></tr>
+                    <tr><td>微积分</td><td><code>Symja.differentiate(expr, var)</code></td></tr>
+                    <tr><td></td><td><code>Symja.integrate(expr, var)</code></td></tr>
+                    <tr><td></td><td><code>Symja.limit(expr, var, point)</code></td></tr>
+                    <tr><td></td><td><code>Symja.series(expr, var, point, order)</code> <small>泰勒展开</small></td></tr>
+                    <tr><td>代数</td><td><code>Symja.solve(eq, var)</code></td></tr>
+                    <tr><td></td><td><code>Symja.simplify(expr)</code></td></tr>
+                    <tr><td></td><td><code>Symja.expand(expr)</code></td></tr>
+                    <tr><td></td><td><code>Symja.factor(expr)</code></td></tr>
+                    <tr><td></td><td><code>Symja.apart(expr, var)</code> <small>部分分式</small></td></tr>
+                    <tr><td></td><td><code>Symja.together(expr)</code> <small>通分</small></td></tr>
+                    <tr><td>矩阵</td><td><code>Symja.det(m)</code></td></tr>
+                    <tr><td></td><td><code>Symja.inverse(m)</code></td></tr>
+                    <tr><td></td><td><code>Symja.transpose(m)</code></td></tr>
+                    <tr><td></td><td><code>Symja.eigenvalues(m)</code></td></tr>
+                    <tr><td>数论</td><td><code>Symja.gcd(a, b)</code></td></tr>
+                    <tr><td></td><td><code>Symja.lcm(a, b)</code></td></tr>
+                    <tr><td></td><td><code>Symja.isPrime(n)</code></td></tr>
+                    <tr><td></td><td><code>Symja.factorInteger(n)</code></td></tr>
+                    <tr><td></td><td><code>Symja.fibonacci(n)</code></td></tr>
+                    <tr><td></td><td><code>Symja.binomial(n, k)</code></td></tr>
+                    <tr><td>数值</td><td><code>Symja.numeric(expr, prec)</code></td></tr>
+                    <tr><td>LaTeX</td><td><code>Symja.toTeX(expr)</code></td></tr>
+                    <tr><td>求和/积</td><td><code>Symja.sum(expr, var, s, e)</code></td></tr>
+                    <tr><td></td><td><code>Symja.product(expr, var, s, e)</code></td></tr>
+                    <tr><td>🎨 绘图</td><td><code>Symja.plot(func, var, xMin, xMax)</code></td></tr>
+                    <tr><td></td><td><code>Symja.parametricPlot(xf, yf, t, tMin, tMax)</code></td></tr>
+                    <tr><td></td><td><code>Symja.listPlot(points)</code></td></tr>
+                    <tr><td>三角</td><td><code>Symja.trigSimplify(expr)</code></td></tr>
                 </table>
                 <p style="font-size: 13px; color: #616161; margin-top: 8px;">
-                    更多 API 请参考完整文档或使用 <code>help</code> 命令
+                    Symja 函数名首字母大写(Sin, Cos, Log, TeXForm)。更多函数使用 <code>help</code> 命令查看。
                 </p>
             </div>
             
             <div class="doc-section">
-                <h4>示例插件</h4>
+                <h4>示例1: 计算器插件</h4>
                 <div class="code-block">{
   "id": "deriv",
   "name": "导数计算器",
@@ -253,17 +242,35 @@
                     <strong>使用:</strong><code>deriv[x^3, x]</code> 或 <code>deriv[{x^2,x^3}, x]</code>(列表参数)
                 </p>
             </div>
-            
+
+            <div class="doc-section">
+                <h4>示例2: 绘图插件</h4>
+                <div class="code-block">{
+  "id": "plot_sin",
+  "name": "正弦曲线绘制器",
+  "icon": "📉",
+  "command": "plotsin",
+  "inputs": [
+    {"name": "amp", "label": "振幅", "defaultValue": "1"},
+    {"name": "freq", "label": "频率", "defaultValue": "1"}
+  ],
+  "jsCode": "function calculate(inputs, Symja) {\n  Symja.print(`绘制 y=${inputs.amp}sin(${inputs.freq}x)`);\n  // plot() 返回绘图JSON,控制台自动渲染为Canvas\n  return Symja.plot(inputs.amp+'*Sin('+inputs.freq+'*x)', 'x', '0', '2*Pi');\n}"
+}</div>
+                <p style="font-size: 13px; color: #616161; margin-top: 8px;">
+                    <strong>使用:</strong><code>plotsin[2, 3]</code> 绘制 y=2sin(3x)
+                </p>
+            </div>
+
             <div class="doc-section">
                 <h4>⚠️ 重要规则</h4>
                 <ul>
                     <li>函数签名:<code>function calculate(inputs, Symja) { ... }</code></li>
-                    <li>输入自动转换为 Symja 可运算类型</li>
-                    <li>必须返回有效的 Symja 表达式</li>
-                    <li>使用 <code>Symja.print()</code> 输出说明</li>
+                    <li>必须返回有效的 Symja 表达式(或 <code>Symja.plot/parametricPlot/listPlot</code> 返回的绘图 JSON)</li>
+                    <li>使用 <code>Symja.print()</code> 输出说明文本</li>
                     <li>使用 <code>throw new Error()</code> 抛出错误</li>
                     <li>返回值可用 <code>%</code> 引用</li>
                     <li>列表参数:<code>cmd[{1,2}, {3,4}]</code> 有 2 个参数</li>
+                    <li>画图请返回 <code>Symja.plot()</code> 而非原始表达式</li>
                 </ul>
             </div>
         </div>

+ 18 - 0
app/src/main/assets/console.js

@@ -1932,6 +1932,24 @@ class PlotRenderer {
         this.bounds.yMin -= padY;
         this.bounds.yMax += padY;
 
+        // 强制等比例:确保圆不变椭圆
+        const m = 60, cw = canvas.width - 2 * m, ch = canvas.height - 2 * m;
+        const xr = this.bounds.xMax - this.bounds.xMin;
+        const yr = this.bounds.yMax - this.bounds.yMin;
+        if (xr > 0 && yr > 0) {
+            if (xr / cw > yr / ch) {
+                const ny = xr * ch / cw;
+                const my = (this.bounds.yMin + this.bounds.yMax) / 2;
+                this.bounds.yMin = my - ny / 2;
+                this.bounds.yMax = my + ny / 2;
+            } else {
+                const nx = yr * cw / ch;
+                const mx = (this.bounds.xMin + this.bounds.xMax) / 2;
+                this.bounds.xMin = mx - nx / 2;
+                this.bounds.xMax = mx + nx / 2;
+            }
+        }
+
         this.transform = { ox: 0, oy: 0, sx: 1, sy: 1 };
         this.draw();
 

+ 11 - 3
app/src/main/java/com/nonvioce/ijs/McpServer.java

@@ -521,15 +521,23 @@ public class McpServer extends NanoHTTPD {
     }
 
     private String callPlot(String function, String variable, String xMin, String xMax) {
-        return symjaEngine.plot(function, variable, xMin, xMax);
+        String result = symjaEngine.plot(function, variable, xMin, xMax);
+        String expr = "Plot[" + function + ", {" + variable + ", " + xMin + ", " + xMax + "}]";
+        AppSession.publishMcpEvent(expr, result);
+        return result;
     }
 
     private String callParametricPlot(String xFunc, String yFunc, String tVar, String tMin, String tMax) {
-        return symjaEngine.parametricPlot(xFunc, yFunc, tVar, tMin, tMax);
+        String result = symjaEngine.parametricPlot(xFunc, yFunc, tVar, tMin, tMax);
+        String expr = "ParametricPlot[{" + xFunc + ", " + yFunc + "}, {" + tVar + ", " + tMin + ", " + tMax + "}]";
+        AppSession.publishMcpEvent(expr, result);
+        return result;
     }
 
     private String callListPlot(String points) {
-        return symjaEngine.listPlot(points);
+        String result = symjaEngine.listPlot(points);
+        AppSession.publishMcpEvent("ListPlot[" + points + "]", result);
+        return result;
     }
 
     private String callExecutePlugin(String pluginId, JSONObject argsObj) {