GRID-CONST.js 50 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638
  1. import scss from "./grid-svg/variables.scss";
  2. import scssCanvas from "./grid-canvas/variables-canvas.scss";
  3. export function getScss(type) {
  4. if (type === "canvas") {
  5. return scssCanvas;
  6. } else {
  7. return scss;
  8. }
  9. }
  10. export const COMMON_CONST = {
  11. idSep: "-",
  12. MAIN_TRACK_DIR: {
  13. DEFAULT: 0,
  14. // 支架的方向
  15. HORIZONTAL: 0, // 横
  16. VERTICAL: 1, // 纵
  17. },
  18. };
  19. export const LOCTYPE = {
  20. default: "default",
  21. rack: "rack",
  22. around: "around",
  23. };
  24. export const ITEM_ATTRIBUTE_TYPE = {
  25. storageLoc: "storageLoc",
  26. dev: "dev",
  27. sysSet: "sysSet",
  28. };
  29. export const ITEMSTATUS = {
  30. default: "default",
  31. storageLoc: "storageLoc",
  32. shuttle: "shuttle",
  33. path: "path",
  34. pathHasDrived: "pathHasDrived",
  35. xTrack: "xTrack",
  36. xTrackEx: "xTrackEx",
  37. carriageway: "carriageway",
  38. lift: "lift",
  39. unExist: "unExist",
  40. unUse: "unUse",
  41. charge: "charge",
  42. entranceAndExit: "entranceAndExit",
  43. park: "park",
  44. transport: "transport",
  45. pillar: "pillar",
  46. goods: "goods",
  47. };
  48. export const getCFG = (type) => {
  49. const scss = getScss(type);
  50. return {
  51. baseItemStsArr: [
  52. {
  53. key: "default",
  54. name: "默认", //用于给默认样式
  55. displayControl: {
  56. isNotShowInCfg: true, // 不在任何配置中显示
  57. },
  58. sty: {
  59. fillColor: scss[ITEMSTATUS.default],
  60. borderColor: scss["borderColor"],
  61. lineWidth: 1,
  62. },
  63. },
  64. {
  65. key: "shuttle",
  66. name: "四向车",
  67. displayControl: {
  68. isNotShowInCfg: true, // 不在任何配置中显示
  69. },
  70. sty: {
  71. fillColor: scss[ITEMSTATUS.shuttle],
  72. },
  73. },
  74. {
  75. key: "path",
  76. name: "路线",
  77. displayControl: {
  78. isNotShowInCfg: true, // 不在任何配置中显示
  79. },
  80. sty: {
  81. fillColor: scss[ITEMSTATUS.path],
  82. lineWidth: 2,
  83. },
  84. },
  85. {
  86. key: "pathHasDrived",
  87. name: "路线",
  88. displayControl: {
  89. isNotShowInCfg: true, // 不在任何配置中显示
  90. },
  91. sty: {
  92. fillColor: scss[ITEMSTATUS.pathHasDrived],
  93. lineWidth: 2,
  94. },
  95. },
  96. {
  97. key: "goods",
  98. name: "货物",
  99. displayControl: {
  100. isNotShowInCfg: true, // 不在任何配置中显示
  101. },
  102. sty: {
  103. fillColor: scss[ITEMSTATUS.goods],
  104. lineWidth: 1,
  105. },
  106. },
  107. {
  108. key: "xTrack",
  109. name: "主轨道",
  110. disableSwitchIsByFloor: true,
  111. handleMouseMove: function (e) {
  112. return false;
  113. },
  114. sty: {
  115. fillColor: scss[ITEMSTATUS.xTrack],
  116. },
  117. cfgTable: {
  118. isNotApplyToOtherFloor: true,
  119. isNotApplyToTotalRow: true,
  120. isNotApplyToTotalCol: true,
  121. columnsCfgArr: function (formData) {
  122. if (!formData.mainTrackDir) {
  123. return [
  124. {
  125. prop: "r",
  126. label: "行",
  127. type: "number",
  128. template: true,
  129. inputProps: {
  130. type: "number",
  131. placeholder: "",
  132. },
  133. },
  134. ];
  135. } else {
  136. return [
  137. {
  138. prop: "c",
  139. label: "列",
  140. type: "number",
  141. template: true,
  142. inputProps: {
  143. placeholder: "",
  144. type: "number",
  145. maxWidth: 100,
  146. },
  147. },
  148. ];
  149. }
  150. },
  151. toPageDataFun: function (formData) {
  152. let res = [];
  153. if (formData[ITEMSTATUS.xTrack]) {
  154. formData[ITEMSTATUS.xTrack].forEach((item) => {
  155. let ele = { c: undefined, r: undefined, f: undefined };
  156. if (!item.mainTrackDir) {
  157. ele.r = item;
  158. } else {
  159. ele.c = item;
  160. }
  161. res.push(ele);
  162. });
  163. }
  164. return res;
  165. },
  166. toBackDataFun: function (formData, cfgTableData) {
  167. let res = [];
  168. if (cfgTableData.length > 0) {
  169. cfgTableData.forEach((item) => {
  170. if (!formData.mainTrackDir) {
  171. res.push(item.r);
  172. } else {
  173. res.push(item.c);
  174. }
  175. });
  176. }
  177. return res;
  178. },
  179. },
  180. cellSelPanel: {
  181. procItemDataFun: function (that) {
  182. const uniqueRowsOrCols = that.getUniqueRowsOrCols();
  183. return that.getOperItemsForLine(uniqueRowsOrCols);
  184. },
  185. },
  186. },
  187. {
  188. key: "xTrackEx",
  189. name: "拓展主轨道",
  190. sty: {
  191. fillColor: scss[ITEMSTATUS.xTrack],
  192. },
  193. displayControl: {
  194. isNotShowInCfgCellSel: true,
  195. },
  196. },
  197. {
  198. key: "carriageway",
  199. backKey: "yTrack",
  200. name: "行车道",
  201. sty: {
  202. fillColor: scss[ITEMSTATUS.carriageway],
  203. },
  204. },
  205. {
  206. key: "lift",
  207. name: "提升机",
  208. disableSwitchIsByFloor: true,
  209. displayControl: {
  210. isNotShowInCfgCellSel: true,
  211. },
  212. sty: {
  213. fillColor: scss[ITEMSTATUS.lift],
  214. },
  215. cfgTable: {
  216. isNotApplyToOtherFloor: true,
  217. isNotApplyToTotalRow: true,
  218. isNotApplyToTotalCol: true,
  219. columnsCfgArr: function (formData) {
  220. return [
  221. {
  222. prop: "did",
  223. label: "did",
  224. template: true,
  225. },
  226. {
  227. prop: "c",
  228. label: "列",
  229. type: "number",
  230. template: true,
  231. inputProps: {
  232. placeholder: "",
  233. type: "number",
  234. },
  235. },
  236. {
  237. prop: "r",
  238. label: "行",
  239. type: "number",
  240. template: true,
  241. inputProps: {
  242. type: "number",
  243. placeholder: "",
  244. },
  245. },
  246. {
  247. prop: "max_floor",
  248. label: "最大层",
  249. type: "number",
  250. template: true,
  251. inputProps: {
  252. type: "number",
  253. placeholder: "",
  254. },
  255. },
  256. {
  257. prop: "rS",
  258. label: "起始行",
  259. type: "number",
  260. template: true,
  261. inputProps: {
  262. type: "number",
  263. placeholder: "",
  264. },
  265. },
  266. {
  267. prop: "rE",
  268. label: "结束行",
  269. type: "number",
  270. template: true,
  271. inputProps: {
  272. type: "number",
  273. placeholder: "",
  274. },
  275. },
  276. {
  277. prop: "cS",
  278. label: "起始列",
  279. type: "number",
  280. template: true,
  281. inputProps: {
  282. type: "number",
  283. placeholder: "",
  284. },
  285. },
  286. {
  287. prop: "cE",
  288. label: "结束列",
  289. type: "number",
  290. template: true,
  291. inputProps: {
  292. type: "number",
  293. placeholder: "",
  294. },
  295. },
  296. ];
  297. },
  298. },
  299. },
  300. {
  301. key: "unUse",
  302. // backKey: 'unUse',
  303. name: "不可用",
  304. sty: {
  305. fillColor: scss[ITEMSTATUS.unUse],
  306. },
  307. },
  308. {
  309. key: "unExist",
  310. // backKey: 'unExist',
  311. name: "不存在",
  312. sty: {
  313. fillColor: scss[ITEMSTATUS.unExist],
  314. },
  315. },
  316. {
  317. key: "park",
  318. name: "停车位",
  319. sty: {
  320. fillColor: scss[ITEMSTATUS.park],
  321. },
  322. },
  323. {
  324. key: "charge",
  325. name: "充电桩",
  326. backKey: "charger",
  327. itemAttributeType: ITEM_ATTRIBUTE_TYPE.dev,
  328. sty: {
  329. fillColor: scss[ITEMSTATUS.charge],
  330. width: 6,
  331. },
  332. cfgTable: {
  333. columnsCfgArr: function (formData) {
  334. return [
  335. {
  336. prop: "did",
  337. label: "did",
  338. template: true,
  339. },
  340. {
  341. prop: "c",
  342. label: "列",
  343. type: "number",
  344. template: true,
  345. inputProps: {
  346. placeholder: "",
  347. type: "number",
  348. },
  349. },
  350. {
  351. prop: "r",
  352. label: "行",
  353. type: "number",
  354. template: true,
  355. inputProps: {
  356. type: "number",
  357. placeholder: "",
  358. },
  359. },
  360. {
  361. prop: "f",
  362. label: "层",
  363. type: "number",
  364. template: true,
  365. inputProps: {
  366. type: "number",
  367. placeholder: "",
  368. },
  369. },
  370. ];
  371. },
  372. },
  373. drawFun: function (that, col) {
  374. const ctx = that.ctx;
  375. ctx.save();
  376. // 设置填充颜色
  377. ctx.fillStyle = this.sty.fillColor;
  378. // 获取坐标
  379. const { x1, y1, x2, y2, x3, y3, x4, y4 } =
  380. that.calculateCoordinates(col);
  381. // 计算矩形的宽度和位置
  382. const width = x2 - x1;
  383. const rectHeight = this.sty.width || 6; // 使用配置的宽度,默认为6
  384. // 在顶部绘制矩形
  385. ctx.fillRect(x1, y1, width, rectHeight);
  386. ctx.restore();
  387. return true;
  388. },
  389. drawFunSvg: function (that, col) {
  390. const group = that.createSvgElement("g");
  391. // 获取坐标和倾斜角度
  392. const { x1, y1, x2, y2, x3, y3, x4, y4 } =
  393. that.component.calculateCoordinates(col);
  394. const angle = that.component.includedAngle || 90;
  395. const angleInRadians = (angle * Math.PI) / 180;
  396. // 计算充电桩的高度
  397. const rectHeight = this.sty.width || 6;
  398. // 计算平行四边形的四个顶点
  399. // a点和b点就是原始的x1,y1和x2,y2
  400. const ax = x1;
  401. const ay = y1;
  402. const bx = x2;
  403. const by = y2;
  404. // 计算单元格的倾斜向量
  405. const cellVectorX = x4 - x1;
  406. const cellVectorY = y4 - y1;
  407. const cellLength = Math.sqrt(
  408. cellVectorX * cellVectorX + cellVectorY * cellVectorY
  409. );
  410. // 计算单位向量
  411. const unitVectorX = cellVectorX / cellLength;
  412. const unitVectorY = cellVectorY / cellLength;
  413. // 使用单元格的倾斜方向计算偏移量
  414. const offsetX = rectHeight * unitVectorX;
  415. const offsetY = rectHeight * unitVectorY;
  416. // 计算c点和d点
  417. const dx = ax + offsetX;
  418. const dy = ay + offsetY;
  419. const cx = bx + offsetX;
  420. const cy = by + offsetY;
  421. // 创建平行四边形
  422. const rect = that.createSvgElement("polygon", {
  423. points: `${ax},${ay} ${bx},${by} ${cx},${cy} ${dx},${dy}`,
  424. fill: this.sty.fillColor,
  425. stroke: "none",
  426. });
  427. group.appendChild(rect);
  428. that.mainGroup.appendChild(group);
  429. return true;
  430. },
  431. },
  432. {
  433. key: "transport",
  434. backKey: "conveyor",
  435. name: "输送机",
  436. itemAttributeType: ITEM_ATTRIBUTE_TYPE.dev,
  437. sty: {
  438. fillColor: scss[ITEMSTATUS.transport],
  439. borderColor: scss[ITEMSTATUS.transport + "BorderColor"],
  440. borderWidth: 4,
  441. },
  442. cfgTable: {
  443. isNotApplyToOtherFloor: true,
  444. isNotApplyToTotalRow: true,
  445. isNotApplyToTotalCol: true,
  446. columnsCfgArr: function (formData) {
  447. return [
  448. {
  449. prop: "did",
  450. label: "did",
  451. template: true,
  452. },
  453. {
  454. prop: "c",
  455. label: "列",
  456. type: "number",
  457. template: true,
  458. inputProps: {
  459. placeholder: "",
  460. type: "number",
  461. },
  462. },
  463. {
  464. prop: "r",
  465. label: "行",
  466. type: "number",
  467. template: true,
  468. inputProps: {
  469. type: "number",
  470. placeholder: "",
  471. },
  472. },
  473. {
  474. prop: "f",
  475. label: "层",
  476. type: "number",
  477. template: true,
  478. inputProps: {
  479. type: "number",
  480. placeholder: "",
  481. },
  482. },
  483. {
  484. prop: "rS",
  485. label: "起始行",
  486. type: "number",
  487. template: true,
  488. inputProps: {
  489. type: "number",
  490. placeholder: "",
  491. },
  492. },
  493. {
  494. prop: "rE",
  495. label: "结束行",
  496. type: "number",
  497. template: true,
  498. inputProps: {
  499. type: "number",
  500. placeholder: "",
  501. },
  502. },
  503. {
  504. prop: "cS",
  505. label: "起始列",
  506. type: "number",
  507. template: true,
  508. inputProps: {
  509. type: "number",
  510. placeholder: "",
  511. },
  512. },
  513. {
  514. prop: "cE",
  515. label: "结束列",
  516. type: "number",
  517. template: true,
  518. inputProps: {
  519. type: "number",
  520. placeholder: "",
  521. },
  522. },
  523. ];
  524. },
  525. },
  526. drawFun: function (that, col) {
  527. const ctx = that.ctx;
  528. ctx.save();
  529. // 设置填充和边框颜色
  530. ctx.fillStyle = this.sty.fillColor;
  531. ctx.strokeStyle = this.sty.borderColor;
  532. const borderWidth = this.sty.borderWidth;
  533. const offset = borderWidth / 2;
  534. // 获取外部轮廓坐标
  535. const { x1, y1, x2, y2, x3, y3, x4, y4 } =
  536. that.calculateCoordinates(col);
  537. // 计算内部偏移量
  538. const dx =
  539. ((x2 - x1) * offset) / Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
  540. const dy =
  541. ((y2 - y1) * offset) / Math.sqrt((x2 - x1) ** 2 + (y2 - y1) ** 2);
  542. // 计算内部轮廓坐标
  543. const ix1 = x1 + dx;
  544. const iy1 = y1 + dy;
  545. const ix2 = x2 - dx;
  546. const iy2 = y2 + dy;
  547. const ix3 = x3 - dx;
  548. const iy3 = y3 - dy;
  549. const ix4 = x4 + dx;
  550. const iy4 = y4 - dy;
  551. // 绘制主体形状
  552. ctx.beginPath();
  553. ctx.moveTo(ix1, iy1);
  554. ctx.lineTo(ix2, iy2);
  555. ctx.lineTo(ix3, iy3);
  556. ctx.lineTo(ix4, iy4);
  557. ctx.closePath();
  558. ctx.fill();
  559. // 绘制左边框
  560. ctx.beginPath();
  561. ctx.lineWidth = borderWidth;
  562. ctx.moveTo(ix1, iy1);
  563. ctx.lineTo(ix4, iy4);
  564. ctx.stroke();
  565. // 绘制右边框
  566. ctx.beginPath();
  567. ctx.moveTo(ix2, iy2);
  568. ctx.lineTo(ix3, iy3);
  569. ctx.stroke();
  570. ctx.restore();
  571. return true;
  572. },
  573. drawFunSvg: function (that, col) {
  574. const group = that.createSvgElement("g");
  575. // 获取坐标和计算偏移量
  576. const { x1, y1, x2, y2, x3, y3, x4, y4 } =
  577. that.component.calculateCoordinates(col);
  578. const borderWidth = this.sty.borderWidth || 4;
  579. const offset = borderWidth / 2;
  580. // 计算倾斜角度
  581. const angle = that.component.includedAngle || 90;
  582. const angleInRadians = (angle * Math.PI) / 180;
  583. // 根据倾斜角度调整右侧偏移量,使视觉效果一致
  584. const rightOffset = offset / Math.sin(angleInRadians);
  585. // 计算内部轮廓坐标
  586. const ix1 = x1 + offset;
  587. const iy1 = y1;
  588. const ix2 = x2 - rightOffset;
  589. const iy2 = y2;
  590. const ix3 = x3 - rightOffset;
  591. const iy3 = y3;
  592. const ix4 = x4 + offset;
  593. const iy4 = y4;
  594. // 创建外部轮廓(左侧平行四边形)
  595. const leftPolygon = that.createSvgElement("polygon", {
  596. points: `${x1},${y1} ${ix1},${iy1} ${ix4},${iy4} ${x4},${y4}`,
  597. fill: this.sty.borderColor,
  598. stroke: "none",
  599. });
  600. // 创建外部轮廓(右侧平行四边形)
  601. const rightPolygon = that.createSvgElement("polygon", {
  602. points: `${x2},${y2} ${ix2},${iy2} ${ix3},${iy3} ${x3},${y3}`,
  603. fill: this.sty.borderColor,
  604. stroke: "none",
  605. });
  606. // 应用偏移量到所有多边形
  607. [leftPolygon, rightPolygon].forEach((polygon) => {
  608. const points = polygon.getAttribute("points");
  609. const offsetPoints = points
  610. .split(" ")
  611. .map((point) => {
  612. const [x, y] = point.split(",");
  613. return `${parseFloat(x)},${parseFloat(y)}`;
  614. })
  615. .join(" ");
  616. polygon.setAttribute("points", offsetPoints);
  617. });
  618. group.appendChild(leftPolygon); // 左边框
  619. group.appendChild(rightPolygon); // 右边框
  620. that.mainGroup.appendChild(group);
  621. return true;
  622. },
  623. getTheTargetStsWhenCfg: function (that, ele) {
  624. if (ele.statusList && Array.isArray(ele.statusList)) {
  625. // 检查 statusList 中是否存在 this.key 的状态
  626. const existingStatus = ele.statusList.find(
  627. (item) => item.status === this.key
  628. );
  629. return existingStatus ? "" : this.key;
  630. }
  631. return this.key;
  632. },
  633. },
  634. {
  635. key: "entranceAndExit",
  636. name: "出入口",
  637. itemAttributeType: ITEM_ATTRIBUTE_TYPE.sysSet,
  638. displayControl: {
  639. isNotShowInCfgCellSel: true,
  640. },
  641. paramInfoArr: [
  642. {
  643. type: "radio",
  644. defaultVal: "",
  645. paramKeyVal: "type",
  646. options: [
  647. { label: "出入口", value: "" },
  648. { label: "出口", value: "exit" },
  649. { label: "入口", value: "entrance" },
  650. ],
  651. },
  652. ],
  653. paramToMergeObj: {
  654. type: "",
  655. arrowFlow: 0,
  656. },
  657. sty: {
  658. arrowFillColor: scss["arrowColor"],
  659. arrowStrokeColor: scss["arrowColor"],
  660. arrowLineWidth: 1,
  661. },
  662. getTheTargetStsWhenCfg: function (that, ele) {
  663. if (ele.statusList && Array.isArray(ele.statusList)) {
  664. // 检查 statusList 中是否存在 this.key 的状态
  665. const existingStatus = ele.statusList.find(
  666. (item) => item.status === this.key
  667. );
  668. const isDisItemSts =
  669. existingStatus &&
  670. (!that.paramToMergeObj.type ||
  671. (existingStatus.paramToMergeObj &&
  672. existingStatus.paramToMergeObj.arrowFlow === 1));
  673. return isDisItemSts ? "" : this.key;
  674. }
  675. return this.key;
  676. },
  677. handleDoubleClick: function (e) {
  678. return false;
  679. },
  680. handleMouseMove: function (e) {
  681. return false;
  682. },
  683. drawFun: function (that, col) {
  684. let arrowType;
  685. const isHorizontal = that.isHorizontal();
  686. const angle = that.rotationAngleType || 0;
  687. // mergeObj.type = 'exit' //TEST
  688. if (col.type === "exit") {
  689. if (isHorizontal) {
  690. switch (angle) {
  691. case 0:
  692. arrowType = "down";
  693. break;
  694. case 1:
  695. arrowType = "left";
  696. break;
  697. case 2:
  698. arrowType = "up";
  699. break;
  700. case 3:
  701. arrowType = "right";
  702. break;
  703. }
  704. } else {
  705. switch (angle) {
  706. case 0:
  707. arrowType = "left";
  708. break;
  709. case 1:
  710. arrowType = "up";
  711. break;
  712. case 2:
  713. arrowType = "right";
  714. break;
  715. case 3:
  716. arrowType = "down";
  717. break;
  718. }
  719. }
  720. } else if (col.type === "entrance") {
  721. if (isHorizontal) {
  722. switch (angle) {
  723. case 0:
  724. arrowType = "up";
  725. break;
  726. case 1:
  727. arrowType = "right";
  728. break;
  729. case 2:
  730. arrowType = "down";
  731. break;
  732. case 3:
  733. arrowType = "left";
  734. break;
  735. }
  736. } else {
  737. switch (angle) {
  738. case 0:
  739. arrowType = "right";
  740. break;
  741. case 1:
  742. arrowType = "down";
  743. break;
  744. case 2:
  745. arrowType = "left";
  746. break;
  747. case 3:
  748. arrowType = "up";
  749. break;
  750. }
  751. }
  752. } else {
  753. // 双向箭头的情况保持不变
  754. if (angle === 1 || angle === 3) {
  755. arrowType = isHorizontal ? "bidirectional-h" : "bidirectional-v";
  756. } else {
  757. arrowType = isHorizontal ? "bidirectional-v" : "bidirectional-h";
  758. }
  759. }
  760. if (col.type && col.arrowFlow === 1) {
  761. const reverseMap = {
  762. up: "down",
  763. down: "up",
  764. left: "right",
  765. right: "left",
  766. };
  767. arrowType = reverseMap[arrowType] || arrowType;
  768. }
  769. that.ctx.fillStyle = this.sty.arrowFillColor;
  770. that.ctx.strokeStyle = this.sty.arrowStrokeColor;
  771. that.ctx.lineWidth = this.sty.arrowLineWidth;
  772. const coordinates = that.calculateCoordinates(col);
  773. drawArrow(that.ctx, coordinates, arrowType);
  774. return "entranceAndExit-drawFun";
  775. },
  776. drawFunSvg: function (that, col) {
  777. const group = that.createSvgElement("g");
  778. let arrowType;
  779. const isHorizontal = that.component.isHorizontal();
  780. const angle = that.component.rotationAngleType || 0;
  781. // 确定箭头类型
  782. if (col.type === "exit") {
  783. if (isHorizontal) {
  784. switch (angle) {
  785. case 0:
  786. arrowType = "down";
  787. break;
  788. case 1:
  789. arrowType = "left";
  790. break;
  791. case 2:
  792. arrowType = "up";
  793. break;
  794. case 3:
  795. arrowType = "right";
  796. break;
  797. }
  798. } else {
  799. switch (angle) {
  800. case 0:
  801. arrowType = "left";
  802. break;
  803. case 1:
  804. arrowType = "up";
  805. break;
  806. case 2:
  807. arrowType = "right";
  808. break;
  809. case 3:
  810. arrowType = "down";
  811. break;
  812. }
  813. }
  814. } else if (col.type === "entrance") {
  815. if (isHorizontal) {
  816. switch (angle) {
  817. case 0:
  818. arrowType = "up";
  819. break;
  820. case 1:
  821. arrowType = "right";
  822. break;
  823. case 2:
  824. arrowType = "down";
  825. break;
  826. case 3:
  827. arrowType = "left";
  828. break;
  829. }
  830. } else {
  831. switch (angle) {
  832. case 0:
  833. arrowType = "right";
  834. break;
  835. case 1:
  836. arrowType = "down";
  837. break;
  838. case 2:
  839. arrowType = "left";
  840. break;
  841. case 3:
  842. arrowType = "up";
  843. break;
  844. }
  845. }
  846. } else {
  847. if (angle === 1 || angle === 3) {
  848. arrowType = isHorizontal ? "bidirectional-h" : "bidirectional-v";
  849. } else {
  850. arrowType = isHorizontal ? "bidirectional-v" : "bidirectional-h";
  851. }
  852. }
  853. if (col.type && col.arrowFlow === 1) {
  854. const reverseMap = {
  855. up: "down",
  856. down: "up",
  857. left: "right",
  858. right: "left",
  859. };
  860. arrowType = reverseMap[arrowType] || arrowType;
  861. }
  862. // 获取坐标
  863. const { x1, y1, x2, y2, x3, y3, x4, y4 } =
  864. that.component.calculateCoordinates(col);
  865. const centerX = (x1 + x2 + x3 + x4) / 4;
  866. const centerY = (y1 + y2 + y3 + y4) / 4;
  867. const width = Math.max(x2 - x1, x3 - x4);
  868. const height = Math.max(y4 - y1, y3 - y2);
  869. // 基准尺寸
  870. const BASE_SIZE = {
  871. arrowWidth: 16, // 减小箭头宽度,使其更协调
  872. arrowLength: 10, // 减小箭头长度,保持比例
  873. bodyThickness: 6, // 减小主体厚度,使其更精致
  874. };
  875. // 计算缩放比例
  876. const minDimension = Math.min(width, height);
  877. const scale = minDimension / 30; // 调整基准缩放比例
  878. const arrowWidth = BASE_SIZE.arrowWidth * scale;
  879. const arrowLength = BASE_SIZE.arrowLength * scale;
  880. const bodyThickness = BASE_SIZE.bodyThickness * scale;
  881. // 创建箭头路径
  882. let pathData = "";
  883. switch (arrowType) {
  884. case "bidirectional-h": {
  885. const bodyWidth = Math.min(width * 0.5, width - 2 * arrowLength);
  886. pathData = `
  887. M ${centerX - bodyWidth / 2} ${centerY - bodyThickness / 2}
  888. L ${centerX + bodyWidth / 2} ${centerY - bodyThickness / 2}
  889. L ${centerX + bodyWidth / 2} ${centerY + bodyThickness / 2}
  890. L ${centerX - bodyWidth / 2} ${centerY + bodyThickness / 2}
  891. Z
  892. M ${centerX - bodyWidth / 2} ${centerY - arrowWidth / 2}
  893. L ${centerX - bodyWidth / 2 - arrowLength} ${centerY}
  894. L ${centerX - bodyWidth / 2} ${centerY + arrowWidth / 2}
  895. Z
  896. M ${centerX + bodyWidth / 2} ${centerY - arrowWidth / 2}
  897. L ${centerX + bodyWidth / 2 + arrowLength} ${centerY}
  898. L ${centerX + bodyWidth / 2} ${centerY + arrowWidth / 2}
  899. Z
  900. `;
  901. break;
  902. }
  903. case "bidirectional-v": {
  904. const bodyHeight = Math.min(
  905. height * 0.5,
  906. height - 2 * arrowLength
  907. );
  908. pathData = `
  909. M ${centerX - bodyThickness / 2} ${centerY - bodyHeight / 2}
  910. L ${centerX + bodyThickness / 2} ${centerY - bodyHeight / 2}
  911. L ${centerX + bodyThickness / 2} ${centerY + bodyHeight / 2}
  912. L ${centerX - bodyThickness / 2} ${centerY + bodyHeight / 2}
  913. Z
  914. M ${centerX - arrowWidth / 2} ${centerY - bodyHeight / 2}
  915. L ${centerX} ${centerY - bodyHeight / 2 - arrowLength}
  916. L ${centerX + arrowWidth / 2} ${centerY - bodyHeight / 2}
  917. Z
  918. M ${centerX - arrowWidth / 2} ${centerY + bodyHeight / 2}
  919. L ${centerX} ${centerY + bodyHeight / 2 + arrowLength}
  920. L ${centerX + arrowWidth / 2} ${centerY + bodyHeight / 2}
  921. Z
  922. `;
  923. break;
  924. }
  925. case "down": {
  926. const bodyHeight = height * 0.5;
  927. pathData = `
  928. M ${centerX - bodyThickness / 2} ${centerY - bodyHeight / 2}
  929. L ${centerX + bodyThickness / 2} ${centerY - bodyHeight / 2}
  930. L ${centerX + bodyThickness / 2} ${centerY + bodyHeight / 2}
  931. L ${centerX + arrowWidth / 2} ${centerY + bodyHeight / 2}
  932. L ${centerX} ${Math.min(
  933. centerY + bodyHeight / 2 + arrowLength,
  934. y4
  935. )}
  936. L ${centerX - arrowWidth / 2} ${centerY + bodyHeight / 2}
  937. L ${centerX - bodyThickness / 2} ${centerY + bodyHeight / 2}
  938. Z
  939. `;
  940. break;
  941. }
  942. case "left": {
  943. const bodyWidth = width * 0.5;
  944. pathData = `
  945. M ${centerX - bodyWidth / 2} ${centerY - bodyThickness / 2}
  946. L ${centerX + bodyWidth / 2} ${centerY - bodyThickness / 2}
  947. L ${centerX + bodyWidth / 2} ${centerY + bodyThickness / 2}
  948. L ${centerX - bodyWidth / 2} ${centerY + bodyThickness / 2}
  949. Z
  950. M ${centerX - bodyWidth / 2} ${centerY - arrowWidth / 2}
  951. L ${Math.max(
  952. centerX - bodyWidth / 2 - arrowLength,
  953. x1
  954. )} ${centerY}
  955. L ${centerX - bodyWidth / 2} ${centerY + arrowWidth / 2}
  956. Z
  957. `;
  958. break;
  959. }
  960. case "up": {
  961. const bodyHeight = height * 0.5;
  962. pathData = `
  963. M ${centerX - bodyThickness / 2} ${centerY - bodyHeight / 2}
  964. L ${centerX + bodyThickness / 2} ${centerY - bodyHeight / 2}
  965. L ${centerX + bodyThickness / 2} ${centerY + bodyHeight / 2}
  966. L ${centerX - bodyThickness / 2} ${centerY + bodyHeight / 2}
  967. Z
  968. M ${centerX - arrowWidth / 2} ${centerY - bodyHeight / 2}
  969. L ${centerX} ${Math.max(
  970. centerY - bodyHeight / 2 - arrowLength,
  971. y1
  972. )}
  973. L ${centerX + arrowWidth / 2} ${centerY - bodyHeight / 2}
  974. Z
  975. `;
  976. break;
  977. }
  978. case "right": {
  979. const bodyWidth = width * 0.5;
  980. pathData = `
  981. M ${centerX - bodyWidth / 2} ${centerY - bodyThickness / 2}
  982. L ${centerX + bodyWidth / 2} ${centerY - bodyThickness / 2}
  983. L ${centerX + bodyWidth / 2} ${centerY - arrowWidth / 2}
  984. L ${Math.min(
  985. centerX + bodyWidth / 2 + arrowLength,
  986. x2
  987. )} ${centerY}
  988. L ${centerX + bodyWidth / 2} ${centerY + arrowWidth / 2}
  989. L ${centerX + bodyWidth / 2} ${centerY + bodyThickness / 2}
  990. L ${centerX - bodyWidth / 2} ${centerY + bodyThickness / 2}
  991. Z
  992. `;
  993. break;
  994. }
  995. }
  996. // 创建SVG路径元素
  997. const path = that.createSvgElement("path", {
  998. d: pathData,
  999. fill: this.sty.arrowFillColor,
  1000. stroke: "none", // 移除描边,使外观更清晰
  1001. transform: `rotate(${that.component.includedAngle}, ${centerX}, ${centerY})`, // 添加旋转变换
  1002. });
  1003. group.appendChild(path);
  1004. that.mainGroup.appendChild(group);
  1005. return "entranceAndExit-drawFunSvg";
  1006. },
  1007. cfgTable: {
  1008. toBackDataFun: function (formData, cfgTableData) {
  1009. let res = [];
  1010. if (cfgTableData.length > 0) {
  1011. cfgTableData.forEach((item) => {
  1012. if (item.type !== "exit" && item.type !== "entrance") {
  1013. item.type = "";
  1014. res.push(item);
  1015. }
  1016. });
  1017. }
  1018. return res;
  1019. },
  1020. },
  1021. },
  1022. {
  1023. key: "storageLoc",
  1024. name: "货位",
  1025. noToBackData: true,
  1026. displayControl: {
  1027. isNotShowInCfgPanel: true, // 不在按钮配置面板显示
  1028. },
  1029. sty: {
  1030. fillColor: scss[ITEMSTATUS.storageLoc],
  1031. },
  1032. },
  1033. {
  1034. key: "digitalInput",
  1035. name: "光电",
  1036. itemAttributeType: ITEM_ATTRIBUTE_TYPE.dev,
  1037. displayControl: {
  1038. isNotShowInCfgCellSel: true,
  1039. },
  1040. cfgTable: {
  1041. columnsCfgArr: function (formData) {
  1042. return [
  1043. {
  1044. prop: "did",
  1045. label: "did",
  1046. template: true,
  1047. },
  1048. {
  1049. prop: "c",
  1050. label: "列",
  1051. type: "number",
  1052. template: true,
  1053. inputProps: {
  1054. placeholder: "",
  1055. type: "number",
  1056. },
  1057. },
  1058. {
  1059. prop: "r",
  1060. label: "行",
  1061. type: "number",
  1062. template: true,
  1063. inputProps: {
  1064. type: "number",
  1065. placeholder: "",
  1066. },
  1067. },
  1068. {
  1069. prop: "f",
  1070. label: "层",
  1071. type: "number",
  1072. template: true,
  1073. inputProps: {
  1074. type: "number",
  1075. placeholder: "",
  1076. },
  1077. },
  1078. ];
  1079. },
  1080. },
  1081. drawFun: function (that, col) {
  1082. return true;
  1083. },
  1084. },
  1085. {
  1086. key: "narrowGate",
  1087. name: "限宽门",
  1088. itemAttributeType: ITEM_ATTRIBUTE_TYPE.dev,
  1089. displayControl: {
  1090. isNotShowInCfgCellSel: true,
  1091. },
  1092. cfgTable: {
  1093. columnsCfgArr: function (formData) {
  1094. return [
  1095. {
  1096. prop: "did",
  1097. label: "did",
  1098. template: true,
  1099. },
  1100. {
  1101. prop: "c",
  1102. label: "列",
  1103. type: "number",
  1104. template: true,
  1105. inputProps: {
  1106. placeholder: "",
  1107. type: "number",
  1108. },
  1109. },
  1110. {
  1111. prop: "r",
  1112. label: "行",
  1113. type: "number",
  1114. template: true,
  1115. inputProps: {
  1116. type: "number",
  1117. placeholder: "",
  1118. },
  1119. },
  1120. {
  1121. prop: "f",
  1122. label: "层",
  1123. type: "number",
  1124. template: true,
  1125. inputProps: {
  1126. type: "number",
  1127. placeholder: "",
  1128. },
  1129. },
  1130. ];
  1131. },
  1132. },
  1133. drawFun: function (that, col) {
  1134. return true;
  1135. },
  1136. },
  1137. {
  1138. key: "codeScanners",
  1139. name: "扫码器",
  1140. backKey: "codeScanner",
  1141. itemAttributeType: ITEM_ATTRIBUTE_TYPE.dev,
  1142. displayControl: {
  1143. isNotShowInCfgCellSel: true,
  1144. },
  1145. cfgTable: {
  1146. columnsCfgArr: function (formData) {
  1147. return [
  1148. {
  1149. prop: "did",
  1150. label: "did",
  1151. template: true,
  1152. },
  1153. {
  1154. prop: "c",
  1155. label: "列",
  1156. type: "number",
  1157. template: true,
  1158. inputProps: {
  1159. placeholder: "",
  1160. type: "number",
  1161. },
  1162. },
  1163. {
  1164. prop: "r",
  1165. label: "行",
  1166. type: "number",
  1167. template: true,
  1168. inputProps: {
  1169. type: "number",
  1170. placeholder: "",
  1171. },
  1172. },
  1173. {
  1174. prop: "f",
  1175. label: "层",
  1176. type: "number",
  1177. template: true,
  1178. inputProps: {
  1179. type: "number",
  1180. placeholder: "",
  1181. },
  1182. },
  1183. ];
  1184. },
  1185. },
  1186. drawFun: function (that, col) {
  1187. return true;
  1188. },
  1189. },
  1190. {
  1191. key: LOCTYPE.around,
  1192. LOCTYPE: LOCTYPE.around,
  1193. name: "货架外围", //用于给默认样式
  1194. locType: LOCTYPE.around,
  1195. noToBackData: true,
  1196. disableSwitchIsByFloor: true,
  1197. sty: {
  1198. btnStyle: {
  1199. noIcon: true,
  1200. },
  1201. fillColor: scss[LOCTYPE.around],
  1202. // numSty:{
  1203. // cellNumFontColor:'white'
  1204. // }
  1205. },
  1206. paramInfoArr: [
  1207. {
  1208. type: "input",
  1209. defaultVal: "",
  1210. paramKeyVal: "up",
  1211. dataType: "number",
  1212. label: "上",
  1213. rules: [
  1214. {
  1215. type: "number",
  1216. min: 0,
  1217. message: "请输入大于等于0的整数",
  1218. trigger: "blur",
  1219. },
  1220. ],
  1221. },
  1222. {
  1223. type: "input",
  1224. defaultVal: "",
  1225. paramKeyVal: "down",
  1226. dataType: "number",
  1227. label: "下",
  1228. rules: [
  1229. {
  1230. type: "number",
  1231. min: 0,
  1232. message: "请输入大于等于0的整数",
  1233. trigger: "blur",
  1234. },
  1235. ],
  1236. },
  1237. {
  1238. type: "input",
  1239. defaultVal: "",
  1240. paramKeyVal: "left",
  1241. label: "左",
  1242. dataType: "number",
  1243. rules: [
  1244. {
  1245. type: "number",
  1246. min: 0,
  1247. message: "请输入大于等于0的整数",
  1248. trigger: "blur",
  1249. },
  1250. ],
  1251. },
  1252. {
  1253. type: "input",
  1254. defaultVal: "",
  1255. paramKeyVal: "right",
  1256. label: "右",
  1257. dataType: "number",
  1258. rules: [
  1259. {
  1260. type: "number",
  1261. min: 0,
  1262. message: "请输入大于等于0的整数",
  1263. trigger: "blur",
  1264. },
  1265. ],
  1266. },
  1267. ],
  1268. // 添加合并参数对象
  1269. paramToMergeObj: {
  1270. up: undefined,
  1271. down: undefined,
  1272. left: undefined,
  1273. right: undefined,
  1274. },
  1275. updateFormDataAround: function (formData) {
  1276. if (!formData.around) {
  1277. formData.around = {};
  1278. }
  1279. Object.keys(this.paramToMergeObj).forEach((key) => {
  1280. formData.around[key] = this.paramToMergeObj[key];
  1281. });
  1282. },
  1283. validateWheConfirmCfg: function (formData, that) {
  1284. // 从this.paramToMergeObj获取参数
  1285. if (!this.paramToMergeObj) {
  1286. console.warn("paramToMergeObj is missing");
  1287. return true;
  1288. }
  1289. // 获取旋转角度
  1290. const rotation = formData.rotation || 0;
  1291. // 计算实际的起始行列
  1292. let rowStart, colStart;
  1293. switch (rotation) {
  1294. case 0: // 0度
  1295. rowStart = this.paramToMergeObj.down || 0;
  1296. colStart = this.paramToMergeObj.left || 0;
  1297. break;
  1298. case 1: // 90度
  1299. rowStart = this.paramToMergeObj.left || 0;
  1300. colStart = this.paramToMergeObj.up || 0;
  1301. break;
  1302. case 2: // 180度
  1303. rowStart = this.paramToMergeObj.up || 0;
  1304. colStart = this.paramToMergeObj.right || 0;
  1305. break;
  1306. case 3: // 270度
  1307. rowStart = this.paramToMergeObj.right || 0;
  1308. colStart = this.paramToMergeObj.down || 0;
  1309. break;
  1310. default:
  1311. rowStart = this.paramToMergeObj.down || 0;
  1312. colStart = this.paramToMergeObj.left || 0;
  1313. }
  1314. // 检查是否在有效范围内
  1315. if (rowStart < 0 || rowStart > formData.rowStart) {
  1316. switch (rotation) {
  1317. case 0: // 0度
  1318. that.$message.error(
  1319. "下侧增加的外围数量超出仓库范围!请调整rowStart或外围下侧数量"
  1320. );
  1321. break;
  1322. case 1: // 90度
  1323. that.$message.error(
  1324. "左侧增加的外围数量超出仓库范围!请调整rowStart或外围左侧数量"
  1325. );
  1326. break;
  1327. case 2: // 180度
  1328. that.$message.error(
  1329. "上侧增加的外围数量超出仓库范围!请调整rowStart或外围上侧数量"
  1330. );
  1331. break;
  1332. case 3: // 270度
  1333. that.$message.error(
  1334. "右侧增加的外围数量超出仓库范围!请调整rowStart或外围右侧数量"
  1335. );
  1336. break;
  1337. default:
  1338. that.$message.error(
  1339. "下侧增加的外围数量超出仓库范围!请调整rowStart或外围下侧数量"
  1340. );
  1341. break;
  1342. }
  1343. return true;
  1344. }
  1345. if (colStart < 0 || colStart > formData.colStart) {
  1346. switch (rotation) {
  1347. case 0: // 0度
  1348. that.$message.error(
  1349. "左侧增加的外围数量超出仓库范围!请调整colStart或外围左侧数量"
  1350. );
  1351. break;
  1352. case 1: // 90度
  1353. that.$message.error(
  1354. "上侧增加的外围数量超出仓库范围!请调整colStart或外围上侧数量"
  1355. );
  1356. break;
  1357. case 2: // 180度
  1358. that.$message.error(
  1359. "右侧增加的外围数量超出仓库范围!请调整colStart或外围右侧数量"
  1360. );
  1361. break;
  1362. case 3: // 270度
  1363. that.$message.error(
  1364. "下侧增加的外围数量超出仓库范围!请调整colStart或外围下侧数量"
  1365. );
  1366. break;
  1367. default:
  1368. that.$message.error(
  1369. "左侧增加的外围数量超出仓库范围!请调整colStart或外围左侧数量"
  1370. );
  1371. break;
  1372. }
  1373. return true;
  1374. }
  1375. return false;
  1376. },
  1377. confirmCfg: function (formData, that) {
  1378. if (!this.paramToMergeObj) {
  1379. return;
  1380. }
  1381. this.updateFormDataAround(formData);
  1382. that.$emit("operCfg", {
  1383. operType: "chgAroundBasicInfo",
  1384. operItemStsObj: this,
  1385. formData,
  1386. });
  1387. },
  1388. cancelCfg: function (formData, that) {
  1389. this.paramToMergeObj = JSON.parse(
  1390. JSON.stringify(this.paramToMergeObjStore)
  1391. );
  1392. this.updateFormDataAround(formData);
  1393. that.$emit("operCfg", {
  1394. operType: "chgAroundBasicInfo",
  1395. operItemStsObj: this,
  1396. formData,
  1397. });
  1398. },
  1399. resetCfg: function (formData, that) {
  1400. this.paramToMergeObj.left = 0;
  1401. this.paramToMergeObj.right = 0;
  1402. this.paramToMergeObj.up = 0;
  1403. this.paramToMergeObj.down = 0;
  1404. this.paramToMergeObjStore = JSON.parse(
  1405. JSON.stringify(this.paramToMergeObj)
  1406. );
  1407. this.updateFormDataAround(formData);
  1408. that.$emit("operCfg", {
  1409. operType: "chgAroundBasicInfo",
  1410. operItemStsObj: this,
  1411. formData,
  1412. });
  1413. },
  1414. handleClick: function (e) {
  1415. return false;
  1416. },
  1417. handleDoubleClick: function (e) {
  1418. return false;
  1419. },
  1420. handleMouseMove: function (e) {
  1421. return false;
  1422. },
  1423. },
  1424. {
  1425. key: "exStorage",
  1426. name: "外围货位",
  1427. displayControl: {
  1428. isNotShowInCfgCellSel: true,
  1429. },
  1430. sty: {
  1431. fillColor: scss[ITEMSTATUS.storageLoc],
  1432. },
  1433. },
  1434. ],
  1435. cellSty: {
  1436. cellLen: 20,
  1437. cellWidth: 52,
  1438. cellNumFont: "12px Arial",
  1439. cellNumFontColor: "#333333",
  1440. widthForFlrNum1: 18,
  1441. cellXOffset: 4,
  1442. widthColInd2: 24,
  1443. cellYOffset: 14,
  1444. cellMinLen: 12,
  1445. cellMaxLen: 40,
  1446. rackIdxNumOffsetLen: 24,
  1447. rackIdxNumFont: "12px Arial",
  1448. rackIdxNumFontColor: "#666",
  1449. rackIdxNumSideYPadding: 8, //考虑文字居中渲染
  1450. rackIdxNumSideXPadding: 0,
  1451. },
  1452. };
  1453. };
  1454. /**
  1455. * 绘制箭头
  1456. * @param {CanvasRenderingContext2D} ctx - Canvas上下文
  1457. * @param {Object} coordinates - 坐标点对象 { x1, y1, x2, y2, x3, y3, x4, y4 }
  1458. * @param {string} type - 箭头类型:'bidirectional-h','bidirectional-v','right','left','up','down'
  1459. */
  1460. function drawArrow(ctx, coordinates, type) {
  1461. const { x1, y1, x2, y2, x3, y3, x4, y4 } = coordinates;
  1462. const centerX = (x1 + x2 + x3 + x4) / 4;
  1463. const centerY = (y1 + y2 + y3 + y4) / 4;
  1464. const width = Math.max(x2 - x1, x3 - x4);
  1465. const height = Math.max(y4 - y1, y3 - y2);
  1466. // 调整基准尺寸,使其更适合小格子
  1467. const BASE_SIZE = {
  1468. arrowWidth: 24, // 减小箭头宽度
  1469. arrowLength: 12, // 减小箭头长度
  1470. bodyThickness: 10, // 减小主体厚度
  1471. };
  1472. // 计算缩放比例,确保箭头完整显示
  1473. const minDimension = Math.min(width, height);
  1474. const scale = minDimension / 40; // 移除最小值限制,让箭头始终按比例缩放
  1475. const arrowWidth = BASE_SIZE.arrowWidth * scale;
  1476. const arrowLength = BASE_SIZE.arrowLength * scale;
  1477. const bodyThickness = BASE_SIZE.bodyThickness * scale;
  1478. switch (type) {
  1479. case "bidirectional-h": {
  1480. const bodyWidth = Math.min(width * 0.4, width - 2 * arrowLength);
  1481. ctx.beginPath();
  1482. // 主体矩形
  1483. ctx.moveTo(centerX - bodyWidth / 2, centerY - bodyThickness / 2);
  1484. ctx.lineTo(centerX + bodyWidth / 2, centerY - bodyThickness / 2);
  1485. ctx.lineTo(centerX + bodyWidth / 2, centerY + bodyThickness / 2);
  1486. ctx.lineTo(centerX - bodyWidth / 2, centerY + bodyThickness / 2);
  1487. // 左侧箭头
  1488. ctx.moveTo(centerX - bodyWidth / 2, centerY - arrowWidth / 2);
  1489. ctx.lineTo(centerX - bodyWidth / 2 - arrowLength, centerY);
  1490. ctx.lineTo(centerX - bodyWidth / 2, centerY + arrowWidth / 2);
  1491. // 右侧箭头
  1492. ctx.moveTo(centerX + bodyWidth / 2, centerY - arrowWidth / 2);
  1493. ctx.lineTo(centerX + bodyWidth / 2 + arrowLength, centerY);
  1494. ctx.lineTo(centerX + bodyWidth / 2, centerY + arrowWidth / 2);
  1495. break;
  1496. }
  1497. case "bidirectional-v": {
  1498. const bodyHeight = Math.min(height * 0.4, height - 2 * arrowLength);
  1499. ctx.beginPath();
  1500. // 主体矩形
  1501. ctx.moveTo(centerX - bodyThickness / 2, centerY - bodyHeight / 2);
  1502. ctx.lineTo(centerX + bodyThickness / 2, centerY - bodyHeight / 2);
  1503. ctx.lineTo(centerX + bodyThickness / 2, centerY + bodyHeight / 2);
  1504. ctx.lineTo(centerX - bodyThickness / 2, centerY + bodyHeight / 2);
  1505. // 上箭头
  1506. ctx.moveTo(centerX - arrowWidth / 2, centerY - bodyHeight / 2);
  1507. ctx.lineTo(centerX, centerY - bodyHeight / 2 - arrowLength);
  1508. ctx.lineTo(centerX + arrowWidth / 2, centerY - bodyHeight / 2);
  1509. // 下箭头
  1510. ctx.moveTo(centerX - arrowWidth / 2, centerY + bodyHeight / 2);
  1511. ctx.lineTo(centerX, centerY + bodyHeight / 2 + arrowLength);
  1512. ctx.lineTo(centerX + arrowWidth / 2, centerY + bodyHeight / 2);
  1513. break;
  1514. }
  1515. case "down": {
  1516. const bodyHeight = height * 0.4;
  1517. ctx.beginPath();
  1518. // 主体矩形
  1519. ctx.moveTo(centerX - bodyThickness / 2, centerY - bodyHeight / 2);
  1520. ctx.lineTo(centerX + bodyThickness / 2, centerY - bodyHeight / 2);
  1521. ctx.lineTo(centerX + bodyThickness / 2, centerY + bodyHeight / 2);
  1522. ctx.lineTo(centerX + arrowWidth / 2, centerY + bodyHeight / 2);
  1523. // 箭头
  1524. ctx.lineTo(centerX, Math.min(centerY + bodyHeight / 2 + arrowLength, y4)); // 确保不超出底部边界
  1525. ctx.lineTo(centerX - arrowWidth / 2, centerY + bodyHeight / 2);
  1526. ctx.lineTo(centerX - bodyThickness / 2, centerY + bodyHeight / 2);
  1527. break;
  1528. }
  1529. case "left": {
  1530. const bodyWidth = width * 0.4;
  1531. ctx.beginPath();
  1532. // 主体矩形
  1533. ctx.moveTo(centerX - bodyWidth / 2, centerY - bodyThickness / 2);
  1534. ctx.lineTo(centerX + bodyWidth / 2, centerY - bodyThickness / 2);
  1535. ctx.lineTo(centerX + bodyWidth / 2, centerY + bodyThickness / 2);
  1536. ctx.lineTo(centerX - bodyWidth / 2, centerY + bodyThickness / 2);
  1537. // 箭头
  1538. ctx.moveTo(centerX - bodyWidth / 2, centerY - arrowWidth / 2);
  1539. ctx.lineTo(Math.max(centerX - bodyWidth / 2 - arrowLength, x1), centerY); // 确保不超出左侧边界
  1540. ctx.lineTo(centerX - bodyWidth / 2, centerY + arrowWidth / 2);
  1541. break;
  1542. }
  1543. case "up": {
  1544. const bodyHeight = height * 0.4;
  1545. ctx.beginPath();
  1546. // 主体矩形
  1547. ctx.moveTo(centerX - bodyThickness / 2, centerY - bodyHeight / 2);
  1548. ctx.lineTo(centerX + bodyThickness / 2, centerY - bodyHeight / 2);
  1549. ctx.lineTo(centerX + bodyThickness / 2, centerY + bodyHeight / 2);
  1550. ctx.lineTo(centerX - bodyThickness / 2, centerY + bodyHeight / 2);
  1551. // 箭头
  1552. ctx.moveTo(centerX - arrowWidth / 2, centerY - bodyHeight / 2);
  1553. ctx.lineTo(centerX, Math.max(centerY - bodyHeight / 2 - arrowLength, y1)); // 确保不超出顶部边界
  1554. ctx.lineTo(centerX + arrowWidth / 2, centerY - bodyHeight / 2);
  1555. break;
  1556. }
  1557. case "right": {
  1558. const bodyWidth = width * 0.4;
  1559. ctx.beginPath();
  1560. // 主体矩形
  1561. ctx.moveTo(centerX - bodyWidth / 2, centerY - bodyThickness / 2);
  1562. ctx.lineTo(centerX + bodyWidth / 2, centerY - bodyThickness / 2);
  1563. ctx.lineTo(centerX + bodyWidth / 2, centerY - arrowWidth / 2);
  1564. ctx.lineTo(Math.min(centerX + bodyWidth / 2 + arrowLength, x2), centerY); // 确保不超出右侧边界
  1565. ctx.lineTo(centerX + bodyWidth / 2, centerY + arrowWidth / 2);
  1566. ctx.lineTo(centerX + bodyWidth / 2, centerY + bodyThickness / 2);
  1567. ctx.lineTo(centerX - bodyWidth / 2, centerY + bodyThickness / 2);
  1568. break;
  1569. }
  1570. }
  1571. ctx.closePath();
  1572. ctx.fill();
  1573. }
  1574. /**
  1575. * 根据条件返回相应的 SCSS 对象
  1576. * @param {string} type - 类型参数,用于决定返回哪个 SCSS 对象
  1577. * @returns {object} - 返回相应的 SCSS 对象
  1578. */