Mapdata.vue 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349
  1. <template>
  2. <div class="mapdata">
  3. <div id="container" ref="container" style="width: 580px"></div>
  4. </div>
  5. </template>
  6. <script>
  7. import Konva from 'konva'
  8. import { selectLotoMapById, selectIsLotoStationById } from '@/api/mes/lotoStation/lotoStation'
  9. import { getTechnologyInfo } from '@/api/system/machinery'
  10. import { selectIsMapById } from '@/api/system/mapconfig'
  11. export default {
  12. name: 'KonvaExample',
  13. props: {
  14. machineryId: {
  15. type: String,
  16. default: ''
  17. }
  18. },
  19. data() {
  20. return {
  21. stage: null,
  22. layer: null,
  23. selectedStates: [], // 用于存储每个元素的选中状态
  24. selectedText: [], // 用于存储未选中的元素文本
  25. rects: [], // 白色r ect合集
  26. texts: [], // 白色text合集
  27. redrects: [], // 红色rect合集
  28. redtexts: [], // 白色text合集
  29. value: '',
  30. form: {}, //拿到单个数据
  31. orignData: null, //原始数据
  32. pointIdList: [], //选中的隔离点
  33. selectPoints: [], //回显之前选中的隔离点
  34. imageUrl: '',//获取底图
  35. width: '',//底图宽
  36. height: '',//底图高
  37. x: '',//底图横坐标
  38. y: '',//底图纵坐标
  39. pointList: null//接口给的所有点位数据
  40. }
  41. },
  42. watch: {
  43. machineryId: {
  44. handler(newValue) {
  45. if (newValue) {
  46. console.log(this.machineryId, 'Mapdata拿到的父组件machineryId')
  47. this.selectIsLotoStationById()
  48. }
  49. },
  50. immediate: true
  51. }
  52. },
  53. mounted() {
  54. this.$nextTick(() => {
  55. if (this.machineryId) {
  56. this.selectIsLotoStationById()
  57. const machineryId = this.machineryId
  58. console.log(machineryId, 'Mapdata拿到的父组件传递数据')
  59. }
  60. })
  61. },
  62. beforeDestroy() { // Vue 2
  63. this.imageUrl = ''
  64. this.pointList = null
  65. },
  66. methods: {
  67. selectIsLotoStationById() {
  68. const machineryId = this.machineryId
  69. getTechnologyInfo(machineryId).then((response) => {
  70. const lotoId = response.data.lotoId
  71. const sopId = ''
  72. const ticketId = ''
  73. selectIsLotoStationById(lotoId).then((response) => {
  74. console.log(response, '电柜信息')
  75. this.form = response.data
  76. // 获取不同底图 如地图或者柜子
  77. selectIsMapById(response.data.mapId).then((response) => {
  78. console.log(response, '获取底图')
  79. this.imageUrl = response.data.imageUrl
  80. this.width = response.data.width
  81. this.height = response.data.height
  82. this.x = response.data.x
  83. this.y = response.data.y
  84. this.pointList = response.data.pointList
  85. this.initKonva()
  86. })
  87. })
  88. // selectLotoMapById(lotoId, sopId, ticketId).then((response) => {
  89. // console.log(response, '电柜预览接口调用')
  90. // this.form.map = response.data
  91. //
  92. // if (response.data) {
  93. // try {
  94. // this.value = JSON.stringify(response.data, null, 4)
  95. // this.orignData = this.value
  96. // } catch (err) {
  97. // }
  98. // }
  99. // this.initKonva()
  100. // })
  101. })
  102. // 设备工艺详情
  103. getTechnologyInfo(this.machineryId).then((response) => {
  104. console.log(response, '设备/工艺详情')
  105. this.selectPoints = response.data.pointIdList
  106. })
  107. },
  108. initKonva() {
  109. // 创建舞台
  110. this.stage = new Konva.Stage({
  111. container: this.$refs.container, // 容器元素
  112. width: 580,
  113. height: 400
  114. })
  115. // 创建底图图层
  116. this.bgLayer = new Konva.Layer()
  117. // 创建底图
  118. const bgImage = new Image()
  119. // bgImage.src = require("@/assets/images/table.png");
  120. bgImage.src = this.imageUrl
  121. if (this.width > 1000) {
  122. bgImage.onload = () => {
  123. const knovaImage = new Konva.Image({
  124. x: this.x,
  125. y: this.y,
  126. image: bgImage,
  127. width: this.width / 2.1,
  128. height: this.height / 2,
  129. draggable: false
  130. })
  131. this.bgLayer.add(knovaImage)
  132. this.bgLayer.draw() // 绘制底图图层
  133. }
  134. } else {
  135. bgImage.onload = () => {
  136. const knovaImage = new Konva.Image({
  137. x: this.x - 220,
  138. y: this.y,
  139. image: bgImage,
  140. width: this.width / 2,
  141. height: this.height / 2,
  142. draggable: false
  143. })
  144. this.bgLayer.add(knovaImage)
  145. this.bgLayer.draw() // 绘制底图图层
  146. }
  147. }
  148. // 将底图图层添加到舞台
  149. this.stage.add(this.bgLayer)
  150. // 创建点位图层
  151. this.layer = new Konva.Layer()
  152. // 将点位图层添加到舞台
  153. this.stage.add(this.layer)
  154. // 禁止舞台拖拽
  155. this.stage.draggable(false)
  156. // 渲染数据
  157. const imageSrc = require('@/assets/images/localSetIcon.jpg') // 图片路径
  158. this.renderGrid(imageSrc, 6, 3, 450, 100, 120, 100, 50, 50, 60, 25)
  159. },
  160. renderGrid(imageSrc) {
  161. this.selectedStates = [] // 用数组存储选中状态
  162. this.rects = {}
  163. this.texts = {}
  164. this.bgrects = {}
  165. this.redrects = {}
  166. this.redtexts = {}
  167. this.selectedText = []
  168. this.pointIdList = [] // 初始化选中的点ID列表
  169. // const positions = JSON.parse(this.value); // 获取点位数据
  170. const positions = this.pointList
  171. console.log(positions, 'positions')
  172. // **计算柜子的布局范围**
  173. const cabinetWidth = this.stage.width() // 柜子的宽度
  174. const cabinetHeight = this.stage.height() // 柜子的高度
  175. const rows = Math.max(...positions.map((p) => p.x)) + 1 // 根据数据动态计算总行数
  176. const cols = Math.max(...positions.map((p) => p.y)) + 1 // 根据数据动态计算总列数
  177. // 调整横向和纵向间距
  178. let horizontalSpacingFactor
  179. let verticalSpacingFactor
  180. if (this.width > 1000) {
  181. horizontalSpacingFactor = 0.4 // 横向间距放大倍数
  182. verticalSpacingFactor = 0.4 // 纵向间距缩小倍数
  183. } else {
  184. horizontalSpacingFactor = 0.75 // 横向间距放大倍数
  185. verticalSpacingFactor = 0.53 // 纵向间距缩小倍数
  186. }
  187. const cellWidth = (cabinetWidth / rows) * horizontalSpacingFactor // 调整横向间距
  188. const cellHeight = (cabinetHeight / cols) * verticalSpacingFactor // 调整纵向间距
  189. // 遍历点位,按行列布局计算位置
  190. positions.forEach((pos) => {
  191. const col = pos.y // 当前点位的列
  192. const row = pos.x // 当前点位的行
  193. // 计算点位的实际位置,确保它们位于柜子显示区域内
  194. let x
  195. let y
  196. if (this.width > 1000) {
  197. // 计算柜子的布局范围
  198. x = row * 2 * 12
  199. y = col * 2 * 12
  200. console.log(pos.x, pos.y, x, y, '我打印了')
  201. } else {
  202. x = row * 2.4 * 12-104
  203. y = col * 2 * 12 + 8
  204. // x = row * cellWidth - 105; //这里之前是间距比较大的时候使用
  205. // y = col * cellHeight + 12;
  206. }
  207. const labelText = pos.entityName // 对应的文字
  208. const point = new Image()
  209. point.src = pos.pointIcon
  210. point.onload = () => {
  211. const knovaImage = new Konva.Image({
  212. x: x + 6, // 适当的偏移确保点位不重叠
  213. y: y + 6, // 适当的偏移确保点位不重叠
  214. image: point,
  215. width: 19,
  216. height: 18,
  217. draggable: false
  218. })
  219. // **绘制背景矩形**(以单元格大小为基础)
  220. const bgrect = new Konva.Rect({
  221. x: x,
  222. y: y,
  223. width: 30,
  224. height: 36,
  225. cornerRadius: 5,
  226. stroke: 'white',
  227. strokeWidth: 2,
  228. fill: 'white'
  229. })
  230. this.layer.add(bgrect)
  231. this.bgrects[labelText] = bgrect
  232. // **普通矩形边框**(同样按照单元格尺寸)
  233. const rect = new Konva.Rect({
  234. x: x + 4,
  235. y: y + 4,
  236. width: 30 - 8,
  237. height: 36 - 8,
  238. cornerRadius: 5,
  239. stroke: 'red',
  240. strokeWidth: 2,
  241. fill: 'white'
  242. })
  243. this.layer.add(rect)
  244. this.rects[labelText] = rect
  245. // 添加图片
  246. this.layer.add(knovaImage)
  247. // **绘制点位的文字**(确保与背景矩形不重叠)
  248. const text = new Konva.Text({
  249. x: x + 8, // 适当的偏移,确保文字不与背景矩形重叠
  250. y: y + 43 - 20, // 文字放在底部
  251. fontSize: 8,
  252. text: labelText,
  253. fontFamily: 'Calibri',
  254. fill: 'red'
  255. })
  256. this.layer.add(text)
  257. this.texts[labelText] = text
  258. // **选中覆盖矩形**(保持与背景矩形相同的尺寸)
  259. const redrect = new Konva.Rect({
  260. x: x,
  261. y: y,
  262. width: 30,
  263. height: 36,
  264. cornerRadius: 5,
  265. fill: 'rgba(97, 97, 97, 0.5)', // 半透明灰色
  266. visible: false, // 初始状态隐藏
  267. listening: false
  268. })
  269. this.layer.add(redrect)
  270. this.redrects[labelText] = redrect
  271. // **对号文字(表示选中)**
  272. const redtext = new Konva.Text({
  273. x: x + 30 / 2 - 5, // 水平居中
  274. y: y + 36 / 2 - 5, // 垂直居中
  275. fontSize: 13,
  276. text: '✔',
  277. fontFamily: 'Arial',
  278. fill: 'white',
  279. align: 'center',
  280. visible: false, // 初始隐藏状态
  281. listening: false
  282. })
  283. this.layer.add(redtext)
  284. this.redtexts[labelText] = redtext
  285. // 如果初始化时有选中的点位
  286. if (
  287. Array.isArray(this.selectPoints) &&
  288. this.selectPoints.length > 0
  289. ) {
  290. if (this.selectPoints.includes(pos.entityId)) {
  291. // 设置选中状态
  292. this.redrects[labelText].visible(true)
  293. this.redtexts[labelText].visible(true)
  294. this.pointIdList.push(pos.entityId) // 添加ID
  295. }
  296. }
  297. this.layer.draw() // 刷新画布
  298. }
  299. })
  300. }
  301. }
  302. }
  303. </script>
  304. <style scoped lang="scss">
  305. #container {
  306. width: 100%;
  307. height: 100%;
  308. }
  309. .mapdata {
  310. width: 100%;
  311. height: 100%;
  312. display: flex;
  313. }
  314. .left {
  315. flex: 1;
  316. display: flex;
  317. flex-direction: column;
  318. }
  319. </style>