最近在想用web页面作为机器人前端的控制界面,以前对前端有点粗浅的技术储备。查了一些资料,发现前端可以设计出非常漂亮的界面,并且可以不限于计算机本地运行,那么如果将机械臂的控制UI用web界面实现是非常有好处的,一个好处是可以实现异地的操控,这不就是传说中的远程控制吗,想象一下这样一副场景:
一个打工仔不用去工厂,在家打开浏览器登录工厂机械臂的工号,就可以操作机械臂干活了,当然这个活是较为精细的,机器智能还不能代替人干的那种。
好了废话不多说,首先web操控界面要实现的是一个布局,本质上是div的摆放,这很简单,但是可能里面涉及到会装入很多的显示内容,并且有可能要中途对div进行缩放的调节,用现成的div好像不太能满足要求。于是就参考了一些网友的文章,做了一个简陋的框框:
如上图,这个框框是可以通过鼠标进行拖拽后调整大小的,然后这个布局是可以通过定义一个对象来调整div的布局的多少的。还用到了web前端的模块化导入技术类似这样:
import { print, clear, createFrame, creatprint } from './lib.js';
1 数据驱动的布局实现
首先来说一下不入流的数据驱动设计,设计思路是用一个js类来定义div布局框架的,目的是通过这个js类的定义,可以定义出任意想要任意数量的div布局,如下:
以上的布局是通过这样的js对象定义的:
var UiItem0 = {
dc: 80,
faterid: '',
style: 'UiItem',
newstyle: {
color: 'blue',
},
name: 'pp',
id: 'test',
width: '100%',
height: '100%',
splitwidth: '5px',
dir: 'V',//垂直分割
boxs: [80, 20] //100为单位,如为非数字则可以再细分
};
var UiItem1 = {
dc: 80,
faterid: '',
style: 'UiItem',
newstyle: {
color: 'blue',
},
name: 'pp1',
id: 'test1',
width: '100%',
height: '100%',
splitwidth: '5px',
dir: 'H',//垂直分割
boxs: [10, UiItem0, 10] //100为单位,如为非数字则可以再细分
};
var UiItem = {
faterid: 'app',
style: 'UiItem',
newstyle: {
color: 'blue',
},
name: 'title',
id: 'title',
width: '100%',
height: '100%',
splitwidth: '5px',
dir: 'H',//垂直分割
boxs: [10, UiItem1, 10] //100为单位,如为非数字则可以再细分
};
只要将上面的UiItem放入创建框架函数 createFrame(UiItem);就可以根据定义的js对象创建出相应的div快,每个块都是可以拖动的。
其中最小的原子数据格式是UiItem对象,其简单的定义如下:
var UiItem = {
faterid: 'app',//父亲div的id
style: 'UiItem',//这个原子div的风格
newstyle: {
color: 'blue',
},//这个原子div的补充风格
name: 'title',//单元div的名称
id: 'title',//单元div的id
width: '100%',//div的宽
height: '100%',
splitwidth: '5px',
dir: 'H',//采用左右垂直分割,就是横向排列
boxs: [10, UiItem1, 10] //在单元div上放上3块子div,100为单位,如为非数字则可以再细分
};
2 布局数据的解析函数
上面定义完原子的div布局函数,我们创建一个函数来对定义进行解析,在数据的驱动下创建出想要的div布局来,核心的代码如下:
var itemDiv = document.createElement("div");
itemDiv.id = UiItem.id;
if (UiItem.faterid != '') {
var farthDiv = document.getElementById(UiItem.faterid);
//如果有父节点创建一个div
farthDiv.appendChild(itemDiv);//将子sonDiv赋值给父parentDiv
} else {
//把div追加到body
//document.getElementsByTagName("body").item(0).appendChild(itemDiv);
document.body.appendChild(itemDiv);
}
if (UiItem.style != '') {
itemDiv.className = UiItem.style;//如果有css属性给子设置class属性
}
else {
//为div添加样式
var style = document.createAttribute("style");
itemDiv.setAttributeNode(style);
itemDiv.style.backgroundColor = UiItem.newstyle.color;//自定义属性
}
itemDiv.style.width = UiItem.width;
itemDiv.style.height = UiItem.height;
var isend = 0;
var splitlines = UiItem.boxs.length - 1;
if (UiItem.dir == 'H') {
var unitD = (itemDiv.clientWidth - splitlines * 6) / 100;
console.log('splitlines', splitlines);
console.log('width', itemDiv.clientWidth);
}
else {
var unitD = (itemDiv.clientHeight - splitlines * 6) / 100;
}
var sondivs = [];
var linedivs = [];
let shange = 0
UiItem.boxs.forEach((sondiv) => {
//创建子块
if (typeof (sondiv) == 'object') {
var sdiv = document.createElement("div");
sdiv.id = sondiv.id + 'sondiv';
sondivs.push(sdiv);
sondiv.faterid = sondiv.id + 'sondiv';
if (UiItem.dir == 'H') {
if (shange == 0) shange = 1; else shange = 0;
sdiv.className = 'HsonDiv' + shange;
if (isend != 100) {
sdiv.style.width = sondiv.dc * unitD / itemDiv.clientWidth * 100 + '%';
console.log('width', sdiv.clientWidth);
}
}
else {
if (shange == 0) shange = 1; else shange = 0;
sdiv.className = 'VsonDiv' + shange;
if (isend != 100) {
sdiv.style.height = sondiv.dc * unitD / itemDiv.clientHeight * 100 + '%';
console.log('Height', sdiv.clientHeight);
}
}
itemDiv.appendChild(sdiv);
createFrame(sondiv);
isend = isend + sondiv.dc;
} else {
if (Number.isInteger(sondiv)) {
var sdiv = document.createElement("div");
sdiv.id = isend + 'sondiv';
sondivs.push(sdiv);
if (UiItem.dir == 'H') {
if (shange == 0) shange = 1; else shange = 0;
sdiv.className = 'HsonDiv' + shange;
if (isend != 100) {
//sdiv.style.width = sondiv * unitD + 'px';
sdiv.style.width = sondiv * unitD / itemDiv.clientWidth * 100 + '%';
console.log('width', sdiv.clientWidth);
}
}
else {
if (shange == 0) shange = 1; else shange = 0;
sdiv.className = 'VsonDiv' + shange;
if (isend != 100) {
//sdiv.style.height = sondiv * unitD + 'px';
sdiv.style.height = sondiv * unitD / itemDiv.clientHeight * 100 + '%';
console.log('Height', sdiv.clientHeight, sondiv * unitD / itemDiv.clientHeight);
}
}
}
itemDiv.appendChild(sdiv);
isend = isend + sondiv;
}
3 再补充一个类似打印终端的div
将来为了方便打印信息的查看,我们在底部挂上一个多行文本输出框,可以作为将来程序运行后一些状态信息的输出。
这样,一个原始的可以任意拖动的div布局框架就完成了。将来可以在这个框架基础上,可以逐步实现整个机器人web控制UI的实现了。
本章所有源码已经上传csdn
源码链接
或者关注公众号获取免费资源链接。