Konva 从入门到实践 - day1 第 1 天实操步骤。准备工作一个现代浏览器Chrome/Edge一个代码编辑器VS Code 或记事本均可几张设备图标图片PNG/SVG暂时可以用占位图代替为了方便测试我假设你的图标文件名为ddj.png和ssx2.png放在与 HTML 同级的images/文件夹下。如果你手头没有对应图片可以先使用任意 50x40 尺寸的纯色图片替代。步骤 1创建 HTML 文件并引入 Konva新建一个index.html用 CDN 引入 Konva你也可以下载到本地。!DOCTYPEhtmlhtmllangzh-CNheadmetacharsetUTF-8titleWCS 设备布局 - Day1/titlestylebody{margin:0;padding:20px;background:#f0f2f5;font-family:sans-serif;}#container{border:1px solid #ccc;background:#fff;width:800px;height:600px;}/style/headbodyh2仓库设备布局 (静态渲染)/h2dividcontainer/div!-- 引入 Konva --scriptsrchttps://unpkg.com/konva9/konva.min.js/scriptscript// 我们的代码将写在这里/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 画布和图层// 创建舞台conststagenewKonva.Stage({container:container,// 对应 div 的 idwidth:800,height:600});// 创建一个图层constlayernewKonva.Layer();stage.add(layer);步骤 4编写图片加载与节点创建函数由于图片加载是异步的我们需要等待所有图片准备好后再统一绘制。// 辅助函数根据设备配置创建 Konva.Image 节点functioncreateDeviceNode(device){returnnewPromise((resolve,reject){constimgnewwindow.Image();img.crossOriginanonymous;// 如果图片在别的域根据需要设置img.onload(){constimageNodenewKonva.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 加载失败使用占位矩形);constrectNodenewKonva.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.srcimages/${device.imgName}.png;});}步骤 5遍历数据并批量渲染asyncfunctionrenderLayout(){// 并发创建所有节点constnodesawaitPromise.all(layoutData.layout.map(devicecreateDeviceNode(device)));// 将所有节点添加到图层nodes.forEach(nodelayer.add(node));// 一次性绘制layer.batchDraw();}// 启动渲染renderLayout().then((){console.log(设备布局渲染完成);console.log(可通过 stage.findOne(#id) 查找节点);});步骤 6测试与验证在项目根目录创建images文件夹放入ddj.png和ssx2.png你可以先随便找两张图片大小尽量接近 50x40。用浏览器打开index.html。你应该能看到两个设备图标出现在画布右侧对应 JSON 中的坐标。按 F12 打开控制台如果图片加载失败会看到警告并且画布上会出现灰色矩形作为占位符。完整代码可直接运行!DOCTYPEhtmlhtmllangzh-CNheadmetacharsetUTF-8titleWCS 设备布局 - Day1 静态渲染/titlestylebody{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/headbodyh2仓库设备布局/h2dividcontainer/divdivclassinfo静态渲染完成。打开控制台可查看节点信息。/divscriptsrchttps://unpkg.com/konva9/konva.min.js/scriptscript// 设备布局数据来自你的 JSONconstlayoutData{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}]};// 创建舞台和图层conststagenewKonva.Stage({container:container,width:800,height:600});constlayernewKonva.Layer();stage.add(layer);// 根据设备配置创建图像节点的异步函数functioncreateDeviceNode(device){returnnewPromise((resolve){constimgnewwindow.Image();img.onload(){constimageNodenewKonva.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 加载失败使用占位矩形);constrectNodenewKonva.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.srcimages/${device.imgName}.png;});}// 渲染所有设备asyncfunctionrenderLayout(){constnodesawaitPromise.all(layoutData.layout.map(devicecreateDeviceNode(device)));nodes.forEach(nodelayer.add(node));layer.batchDraw();console.log(所有设备节点已添加到图层并绘制);console.log(示例查找堆垛机节点,stage.findOne(#1782803001807));}renderLayout();/script/body/html第 1 天总结完成以上步骤后你已经掌握了Konva 的Stage → Layer → Node结构如何从 JSON 数据动态创建图片节点如何处理异步图片加载x, y, rotation属性的直接映射为节点附加自定义业务属性如deviceCode、moveLength为后面的交互做准备明天我们将在这些节点上添加拖拽和选中高亮让画面可编辑。如果你在运行过程中遇到任何报错直接把错误信息发来我帮你定位。