上周末人闲事少,参考这个帖子( gdip 绘制主从关系节点图),我试着用 【aardio + 阿里秒悟AI】做了一个简单的思维导图程序。
给这个小程序起了个名字叫《喵呜导图》(MeowMap),文件很小只有 3.6MB (也没有upx压缩),不过麻鹃虽小,五脏俱全,基本的功能都有:比如鼠标左键/中键拖动、鼠标框选、按下shift多选、滚轮缩放;打开、保存、导出png/pdf等。
程序放在下面的附件,欢迎大家测评。🌹🌹


这个程序的业务逻辑主要是秒悟AI写的前端代码,aardio负责加载页面和拦截页面中一些按钮事件。
知识点都在下例中:
import win.ui;
import web.json;
import fsys;
import fsys.dlg;
import crypt;
/*DSG{{*/
var winform = win.form(text="aardio form";right=1063;bottom=655)
/*}}*/
import web.view;
var wv = web.view(winform);
wv.external = {
// 拦截【打开】(JSON)
onOpenFile = function(){
var path = fsys.dlg.open("思维导图(*.mindflow)|*.mindflow","选择思维导图文件",,winform);
if(path){
var jsonStr = string.load(path);
if(jsonStr){
//加载json到画布
wv.doScript("window.api.loadData(" + jsonStr + ");");
}
}
return true;
};
// 拦截【保存】(JSON)
saveToLocalDisk = function(jsonStr){
var result = web.json.parse(jsonStr);
if(result && result.success) {
var path = fsys.dlg.save("思维导图|*.mindflow","保存思维导图",,winform,,result.fileName);
if(path){
string.save(path, result.json);
winform.msgbox("思维导图保存成功!","提示");
}
}
return true;
};
// 拦截【导出PNG】、【导出PDF】
saveBinaryFile = function(fileType, resObj){
if(!resObj) return;
var dataUrl = resObj.base64;
var defaultName = resObj.fileName;
var ext = (fileType == "png") ? "png" : "pdf";
var filter = (fileType == "png") ? "图片|*.png" : "PDF文档|*.pdf";
var path = fsys.dlg.save(filter, "导出" + string.upper(ext), , winform, , defaultName);
if(path){
var base64Data = string.match(dataUrl, "base64,(.+)$"):dataUrl;
var bin = crypt.decodeBin(base64Data);
string.save(path, bin);
winform.msgbox(ext + "文件导出成功!","提示");
}
return true;
};
}
// 注入拦截脚本
wv.preloadScript(`
(function() {
async function handleIntercept(e) {
var btn = e.target.closest('button');
if (!btn) return;
var match = (selector) => btn.querySelector(selector) !== null;
var isMatchOpen = match('svg.lucide-folder-open');
var isMatchSave = match('svg.lucide-save');
var isMatchPng = match('svg.lucide-image');
var isMatchPdf = match('svg.lucide-notebook');
if (isMatchOpen || isMatchSave || isMatchPng || isMatchPdf) {
e.preventDefault();
e.stopPropagation();
e.stopImmediatePropagation();
if (e.type === 'pointerdown' || e.type === 'mousedown') {
if (isMatchOpen) {
setTimeout(() => aardio.onOpenFile(), 0);
}
elseif (isMatchSave) {
const data = api.exportData();
if(data) aardio.saveToLocalDisk(data); }
}elseif (isMatchPng) {
const result = await api.exportPNG();
if(result.success) aardio.saveBinaryFile('png', result);
}elseif (isMatchPdf) {
const result = await api.exportPDF();
if(result.success) aardio.saveBinaryFile('pdf', result);
}
}
return false;
}
}
})();
`);
//启动本地服务器
import wsock.tcp.simpleHttpServer;
var url = wsock.tcp.simpleHttpServer.startUrl("/res/index.html")
wv.go(url);
winform.show(3/*_SW_MAXIMIZE*/);
win.loopMessage();