Konva 从入门到实践 - day1
2026/7/2 20:47:14 网站建设 项目流程

第 1 天实操步骤。


准备工作

  • 一个现代浏览器(Chrome/Edge)
  • 一个代码编辑器(VS Code 或记事本均可)
  • 几张设备图标图片(PNG/SVG),暂时可以用占位图代替

为了方便测试,我假设你的图标文件名为ddj.pngssx2.png,放在与 HTML 同级的images/文件夹下。
如果你手头没有对应图片,可以先使用任意 50x40 尺寸的纯色图片替代。


步骤 1:创建 HTML 文件并引入 Konva

新建一个index.html,用 CDN 引入 Konva(你也可以下载到本地)。

<!DOCTYPEhtml><htmllang="zh-CN"><head><metacharset="UTF-8"><title>WCS 设备布局 - Day1</title><style>body{margin:0;padding:20px;background:#f0f2f5;font-family:sans-serif;}#container{border:1px solid #ccc;background:#fff;width:800px;height:600px;}</style></head><body><h2>仓库设备布局 (静态渲染)</h2><divid="container"></div><!-- 引入 Konva --><scriptsrc="https://unpkg.com/konva@9/konva.min.js"></script><script>// 我们的代码将写在这里</script></body></html>

步骤 2:准备设备布局数据

把我们之前看到的 JSON 整理成一个 JavaScript 对象,放在<script>里。
为了让数据更纯粹,我移除了第二个元素里嵌套的value业务字段,只保留一个selected标志(如果你需要它)。

constlayoutData={description:null,name:null,layout:[{id:"1782803001807",deviceCode:"stacker",imgName:"ddj",left:480,top:275,width:50,height:40,angle:0,moveLength:200,plcMax:null,plcMin:null,selected:false},{id:"1782803143726",deviceCode:"conveyor",// 假设这是一个输送线设备imgName:"ssx2",left:540,top:240,width:50,height:40,angle:0,moveLength:null,plcMax:null,plcMin:null,selected:false}]};

步骤 3:创建 Konva 画布和图层

// 创建舞台conststage=newKonva.Stage({container:'container',// 对应 div 的 idwidth:800,height:600});// 创建一个图层constlayer=newKonva.Layer();stage.add(layer);

步骤 4:编写图片加载与节点创建函数

由于图片加载是异步的,我们需要等待所有图片准备好后再统一绘制。

// 辅助函数:根据设备配置创建 Konva.Image 节点functioncreateDeviceNode(device){returnnewPromise((resolve,reject)=>{constimg=newwindow.Image();img.crossOrigin="anonymous";// 如果图片在别的域,根据需要设置img.onload=()=>{constimageNode=newKonva.Image({id:device.id,image:img,x:device.left,y:device.top,width:device.width,height:device.height,rotation:device.angle,// Konva 默认旋转中心是图片左上角// 如果需要绕中心旋转,可设置 offsetX/offsetY,但这里角度为0,暂不需要// 把业务数据也挂到自定义属性上,供后续使用deviceCode:device.deviceCode,moveLength:device.moveLength,selected:device.selected});resolve(imageNode);};img.onerror=()=>{// 如果图片不存在,用一个矩形占位console.warn(`图片${device.imgName}.png 加载失败,使用占位矩形`);constrectNode=newKonva.Rect({id:device.id,x:device.left,y:device.top,width:device.width,height:device.height,fill:'#cccccc',stroke:'#333',strokeWidth:1,rotation:device.angle});resolve(rectNode);};// 假设图片放在 images 文件夹下img.src=`images/${device.imgName}.png`;});}

步骤 5:遍历数据并批量渲染

asyncfunctionrenderLayout(){// 并发创建所有节点constnodes=awaitPromise.all(layoutData.layout.map(device=>createDeviceNode(device)));// 将所有节点添加到图层nodes.forEach(node=>layer.add(node));// 一次性绘制layer.batchDraw();}// 启动渲染renderLayout().then(()=>{console.log('设备布局渲染完成');console.log('可通过 stage.findOne("#id") 查找节点');});

步骤 6:测试与验证

  1. 在项目根目录创建images文件夹,放入ddj.pngssx2.png(你可以先随便找两张图片,大小尽量接近 50x40)。
  2. 用浏览器打开index.html
  3. 你应该能看到两个设备图标出现在画布右侧(对应 JSON 中的坐标)。
  4. 按 F12 打开控制台,如果图片加载失败,会看到警告,并且画布上会出现灰色矩形作为占位符。

完整代码(可直接运行)

<!DOCTYPEhtml><htmllang="zh-CN"><head><metacharset="UTF-8"><title>WCS 设备布局 - Day1 静态渲染</title><style>body{margin:0;padding:20px;background:#f0f2f5;font-family:sans-serif;}#container{border:1px solid #ccc;background:#fff;width:800px;height:600px;}.info{margin-top:10px;font-size:14px;color:#666;}</style></head><body><h2>仓库设备布局</h2><divid="container"></div><divclass="info">静态渲染完成。打开控制台可查看节点信息。</div><scriptsrc="https://unpkg.com/konva@9/konva.min.js"></script><script>// 设备布局数据(来自你的 JSON)constlayoutData={description:null,name:null,layout:[{id:"1782803001807",deviceCode:"stacker",imgName:"ddj",left:480,top:275,width:50,height:40,angle:0,moveLength:200,plcMax:null,plcMin:null,selected:false},{id:"1782803143726",deviceCode:"conveyor",imgName:"ssx2",left:540,top:240,width:50,height:40,angle:0,moveLength:null,plcMax:null,plcMin:null,selected:false}]};// 创建舞台和图层conststage=newKonva.Stage({container:'container',width:800,height:600});constlayer=newKonva.Layer();stage.add(layer);// 根据设备配置创建图像节点的异步函数functioncreateDeviceNode(device){returnnewPromise((resolve)=>{constimg=newwindow.Image();img.onload=()=>{constimageNode=newKonva.Image({id:device.id,image:img,x:device.left,y:device.top,width:device.width,height:device.height,rotation:device.angle,// 附加自定义属性deviceCode:device.deviceCode,moveLength:device.moveLength,selected:device.selected});resolve(imageNode);};img.onerror=()=>{console.warn(`图片${device.imgName}.png 加载失败,使用占位矩形`);constrectNode=newKonva.Rect({id:device.id,x:device.left,y:device.top,width:device.width,height:device.height,fill:'#cccccc',stroke:'#333',strokeWidth:1,rotation:device.angle,deviceCode:device.deviceCode,moveLength:device.moveLength,selected:device.selected});resolve(rectNode);};img.src=`images/${device.imgName}.png`;});}// 渲染所有设备asyncfunctionrenderLayout(){constnodes=awaitPromise.all(layoutData.layout.map(device=>createDeviceNode(device)));nodes.forEach(node=>layer.add(node));layer.batchDraw();console.log('所有设备节点已添加到图层并绘制');console.log('示例:查找堆垛机节点',stage.findOne('#1782803001807'));}renderLayout();</script></body></html>

第 1 天总结

完成以上步骤后,你已经掌握了:

  • Konva 的Stage → Layer → Node结构
  • 如何从 JSON 数据动态创建图片节点
  • 如何处理异步图片加载
  • x, y, rotation属性的直接映射
  • 为节点附加自定义业务属性(如deviceCodemoveLength),为后面的交互做准备

明天我们将在这些节点上添加拖拽和选中高亮,让画面可编辑。
如果你在运行过程中遇到任何报错,直接把错误信息发来,我帮你定位。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询