# 乐吾乐大屏上动态绘制多个图元并给图元绑定事件
自动渲染界面上的图元
公司最近用乐吾乐大屏可视化组态软件这个编辑工具,因为工具支持以2D/2.5D等形式构建实时数据展示、监控告警、动态交互的组态画面,完全满足国产化需求。(上面这么多基本不用看 我就是复制官网的介绍语介绍下)其实主要是目的就是把自己写的东西记录下来!
开始
1. 绘制图元,并给图元绑定事件,点击查看图元的详情数据
在初始化中写代码
// 初始化 - 保留特定文字版本
const initializeCanvas = () => {
if (!context.meta2d) return;
// 1. 先识别并保留左上角文字元素
const titleTextId = 'title_text'; // 假设文字元素的ID,需要根据实际情况调整
const elementsToKeep = [titleTextId]; // 可以添加多个需要保留的元素的ID
// 2. 获取所有现有图元
const allPens = context.meta2d.store.data.pens || [];
const pensToDelete = [];
// 3. 筛选需要删除的图元(瓶子和线条)
allPens.forEach(pen => {
const shouldKeep = elementsToKeep.includes(pen.id);
if (!shouldKeep) {
// 删除瓶子、线条和其他不需要的图元
if (pen.id && (pen.id.startsWith('bottle_') || pen.id.startsWith('separator_') || pen.name === 'line')) {
pensToDelete.push(pen.id);
}
} else {
console.log(`保留元素: ${pen.id}`, pen);
}
});
// 4. 批量删除不需要的图元
pensToDelete.forEach(penId => {
const pen = context.meta2d.findOne(penId);
if (pen) {
context.meta2d.delete(pen);
}
});
// 5. 清理线条平滑设置(只针对需要删除的图元)
allPens.forEach(pen => {
if (pen.lineSmooth && !elementsToKeep.includes(pen.id)) {
context.meta2d.setValue({ id: pen.id, lineSmooth: undefined });
}
});
// 6. 延迟执行瓶子生成,确保清理完成
setTimeout(() => {
generateBottlesAndLines();
}, 100);
};
// 生成瓶子和线条的完整逻辑
const generateBottlesAndLines = () => {
const bottleImage = "/file/2025/0818/1/1/瓶子22_83ab1a9c.png";
const rows = 12;
const cols = 30;
const horizontalSpacing = 5;
const verticalSpacing = 20;
const startX = 83;
const startY = 130;
const bottleSizeW = 52;
const bottleSizeH = 52;
const defaultBottleData = {
packCode: "0",
show: 0, // 初始为隐藏状态
depositTime: "测试数据",
dueTime: "测试数据",
isOverDue: "测试"
};
// 生成瓶子
for (let row = 1; row <= rows; row++) {
for (let col = 1; col <= cols; col++) {
const bottleId = `bottle_${row}_${col}`;
const pos = `${row}_${col}`;
// 检查瓶子是否已存在
const existingBottle = context.meta2d.findOne(bottleId);
if (existingBottle) {
continue; // 如果已存在,跳过创建
}
const penData = {
id: bottleId,
data: { ...defaultBottleData, pos }
};
const encodedPen = encodeURIComponent(JSON.stringify(penData));
// 创建新瓶子
context.meta2d.addPen({
image: bottleImage,
x: startX + (col - 1) * (bottleSizeW + horizontalSpacing),
y: startY + (row - 1) * (bottleSizeH + verticalSpacing),
width: bottleSizeW,
height: bottleSizeH,
id: bottleId,
name: "image",
visible: defaultBottleData.show == 1, // 初始隐藏
data: { ...defaultBottleData, pos },
events: [
{
name: "click",
conditions: [],
actions: [
{
action: 14,
extend: {
width: 600,
height: 400
},
value: "存样瓶详情",
params: `http://192.0.0.0:8345/view/v/?id=0199cc14-6b35-741a-a18a-67cd829ed32b&pen=${encodedPen}`,
}
]
}
],
}, true, true, true);
}
// 在每行下方添加分隔线
if (row <= rows) {
const separatorId = `separator_${row}`;
// 检查分隔线是否已存在
const existingLine = context.meta2d.findOne(separatorId);
if (existingLine) {
continue;
}
const currentRowBottom = startY + (row - 1) * (bottleSizeH + verticalSpacing) + bottleSizeH;
const nextRowTop = startY + row * (bottleSizeH + verticalSpacing);
const lineY = currentRowBottom + (nextRowTop - currentRowBottom) / 2;
const lineStartX = startX - horizontalSpacing;
const lineEndX = startX + cols * (bottleSizeW + horizontalSpacing) - horizontalSpacing;
context.meta2d.addPen({
name: 'line',
x: lineStartX,
y: lineY,
width: lineEndX - lineStartX,
height: 0,
lineWidth: 1,
strokeStyle: '#cccccc',
dash: 5,
id: separatorId,
}, true, true, true);
}
}
// 最后重绘画布
setTimeout(() => {
context.meta2d.render();
}, 50);
};
// 调用初始化
initializeCanvas();
2. 从webscoker接口获取数据,并更新图元信息元素
创建一个ws接口
然后在解析中写:
meta2d.socketFn = (message, context) => {
try {
const newArr = JSON.parse(message);
const tempMap = {};
// 找到 ggName 为 "1"
const targetItem = newArr.find(item => item.ggName === "1");
if (targetItem && targetItem.detailA) {
targetItem.detailA.forEach(detail => {
const key = detail.pos;
if (key) {
tempMap[key] = {
packCode: detail.packCode || "0",
show: detail.show || 1,
depositTime: detail.depositTime || "",
dueTime: detail.dueTime || "",
isOverDue: detail.isOverDue || "无"
};
}
});
}
// 动态更新瓶子数据(无需重新渲染)
Object.keys(tempMap).forEach(pos => {
const pen = meta2d.findOne(`bottle_${pos}`);
if (pen) {
// 1. 更新 pen.data
pen.data = {
...tempMap[pos],
pos: pen.data.pos, // 保留初始的 pos
};
// 2. show:0-隐藏瓶子;1-显示瓶子;2-过期的瓶子,着色显示
if (tempMap[pos].show == 1) {
meta2d.setVisible(pen, true);
} else if (tempMap[pos].show == 0) {
meta2d.setVisible(pen, false);
} else if (tempMap[pos].show == 2) {
meta2d.setVisible(pen, true);
meta2d.setValue({
id: pen.id,
image: '/file/2025/0825/1/1/瓶子red_146aa0ee.png'
})
}
// 3. 更新 events 里的 params(动态生成新的 URL)
if (tempMap[pos].show != 0) {
const newPenData = { id: pen.id, data: pen.data, ggName: '1', detail: 'A' };
const newEncodedPen = encodeURIComponent(JSON.stringify(newPenData));
const newParams = `http://192.10.10.0:8345/view/v/?id=0199cc14-6b35-741a-a18a-67cd829ed32b&pen=${newEncodedPen}`;
// 使用setProps方法更新事件
meta2d.setValue({
id: pen.id,
events: [{
name: "click",
conditions: [],
actions: [{
action: 14,
extend: { width: 600, height: 400 },
value: "存样瓶详情",
params: newParams
}]
}]
}, { render: true });
}
}
});
meta2d.render();
return { data: Object.values(tempMap) };
} catch (error) {
console.error("MQTT 数据解析失败:", error);
return { data: [] };
}
};
结束语
这种写法可以避免逐个绑定的低效操作,操作效率提升,支持百级体量实时管理。