baseEditer.vue 19 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618
  1. <template>
  2. <div id="baseEditer" ref="graphy">
  3. <div id="fengMap"></div>
  4. <div class="canvas-container">
  5. <canvas id="canvas" :width="canvasWidth" :height="canvasHeight" ref="canvas" tabindex="0"></canvas>
  6. </div>
  7. </div>
  8. </template>
  9. <script>
  10. import { SFengParser } from "@saga-web/feng-map";
  11. import { SFloorParser } from "@saga-web/big";
  12. import { FloorView } from "./../lib/FloorView";
  13. import { EditScence } from "./mapClass/EditScence";
  14. import bus from "@/bus";
  15. import {
  16. saveGroup,
  17. readGroup,
  18. queryTypeGraph,
  19. publishGraph
  20. } from "@/api/editer.js";
  21. import { STopologyParser } from "./../lib/parsers/STopologyParser";
  22. import { uuid } from "@/components/mapClass/until";
  23. import { SImageItem } from "@saga-web/graph/lib";
  24. import { SPainter, SColor, SFont, SPoint } from "@saga-web/draw";
  25. import store from "../store";
  26. import { Loading } from "element-ui";
  27. import { Message } from "element-ui";
  28. let fengmap = null;
  29. //// 底图空间增加字段 isExtracted:boolean true 已被提取过
  30. export default {
  31. props: {
  32. cmdType: {
  33. type: String,
  34. default: "choice",
  35. required: false
  36. },
  37. changeTextMsg: {
  38. type: String,
  39. default: "",
  40. required: false
  41. }
  42. },
  43. data() {
  44. return {
  45. appName: "万达可视化系统",
  46. key: "23f30a832a862c58637a4aadbf50a566",
  47. mapServerURL: "http://map.wanda.cn/editor",
  48. canvasWidth: 700,
  49. canvasHeight: 800,
  50. fParser: null,
  51. scene: null,
  52. view: null,
  53. floorList: {},
  54. urlMsg: {},
  55. chiceItemList: [], //选中itemlist
  56. hasTypeList: [], // 当前类型下包含的typeid(提取)
  57. graphId: "",
  58. initScale: 1, //加载好底图之后的,初始缩放比例
  59. changeScaleByClick: false //区分 滚轮,点击 事件改变的缩放比例
  60. };
  61. },
  62. mounted() {
  63. this.canvasWidth = this.$refs.graphy.offsetWidth;
  64. this.canvasHeight = this.$refs.graphy.offsetHeight - 10;
  65. this.init();
  66. // 挂在bus
  67. this.getBus();
  68. store.dispatch("getElementType", { PageSize: 1000 });
  69. window.vm = this;
  70. const that = this;
  71. document.onkeydown = function(event) {
  72. const e = event || window.event || arguments.callee.caller.arguments[0];
  73. if (e && e.key == "Control") {
  74. // 按 ctrl
  75. that.scene.isDownCtrl = true;
  76. }
  77. };
  78. document.onkeyup = function(event) {
  79. const e = event || window.event || arguments.callee.caller.arguments[0];
  80. if (e && e.key == "Control") {
  81. // 按 ctrl
  82. that.scene.isDownCtrl = false;
  83. this.scene.setCmd = "choice";
  84. }
  85. };
  86. },
  87. methods: {
  88. init() {
  89. const loadings = Loading.service({
  90. lock: true,
  91. text: "Loading",
  92. spinner: "el-icon-loading",
  93. background: "rgba(0, 0, 0, 0.7)"
  94. });
  95. document.getElementById(`canvas`).focus();
  96. this.clearGraphy();
  97. this.scene = new EditScence();
  98. fengmap = new SFengParser(
  99. "fengMap",
  100. this.mapServerURL + "/fmap/" + this.urlMsg.fmapID,
  101. this.key,
  102. this.appName,
  103. null
  104. );
  105. const floorid = this.urlMsg.FloorID;
  106. fengmap.loadMap(this.urlMsg.fmapID, resp => {
  107. this.floorList = resp;
  108. fengmap
  109. .loadTheme(
  110. `${this.mapServerURL}/webtheme/${this.urlMsg.fmapID}/${this.urlMsg.fmapID}.theme`
  111. )
  112. .then(response => {
  113. console.log("获取rf成功", response);
  114. this.parserData(floorid);
  115. this.readGraph();
  116. loadings.close();
  117. });
  118. this.view.fitSceneToView();
  119. });
  120. // 获取typeid
  121. this.getTypeId();
  122. this.scene.emitChange = this.emitChange;
  123. this.scene.scenceUpdate = this.scenceUpdate;
  124. },
  125. parserData(floor) {
  126. if (floor == "g80") {
  127. // 屋顶
  128. if (fengmap.frImg) {
  129. const imgItem = new SImageItem(
  130. null,
  131. `${this.mapServerURL}/webtheme/${this.urlMsg.fmapID}/${fengmap.frImg}`
  132. );
  133. this.scene.addItem(imgItem);
  134. this.view.scene = this.scene;
  135. this.view.fitSceneToView();
  136. this.loading = false;
  137. this.isQuerying = false;
  138. }
  139. } else {
  140. if (this.floorList[floor]) {
  141. fengmap.parseData(this.floorList[floor], res => {
  142. if (res.err) {
  143. console.log(res.err);
  144. return;
  145. }
  146. this.fParser = new SFloorParser(null);
  147. this.fParser.parseData(res);
  148. this.scene.fidToItem = {};
  149. this.fParser.spaceList.forEach(t => {
  150. t.zOrder = t.zOrder + t.data.Height;
  151. t.selectable = true;
  152. this.scene.fidToItem[t.data.SourceId] = t;
  153. this.scene.addItem(t);
  154. });
  155. this.scene.spaceList = this.fParser.spaceList;
  156. this.fParser.wallList.forEach(t => this.scene.addItem(t));
  157. this.fParser.virtualWallList.forEach(t => this.scene.addItem(t));
  158. this.fParser.doorList.forEach(t => this.scene.addItem(t));
  159. this.fParser.columnList.forEach(t => this.scene.addItem(t));
  160. this.fParser.casementList.forEach(t => this.scene.addItem(t));
  161. this.view.scene = this.scene;
  162. this.view.fitSceneToView();
  163. this.loading = false;
  164. this.isQuerying = false;
  165. console.log("success");
  166. // 设置初始化缩放比例
  167. this.initScale = this.view.scale;
  168. bus.$emit("initScale", this.view.scale);
  169. });
  170. } else {
  171. console.log("楼层不正确");
  172. }
  173. }
  174. },
  175. // 读取绘制数据
  176. readGraph() {
  177. this.readGroup().then(data => {
  178. this.graphId = data.Data[0].ID;
  179. bus.$emit("setGraphId", this.graphId);
  180. if (data.Data) {
  181. const parserData = new STopologyParser(null);
  182. const itemMap = {};
  183. parserData.parseData(data.Data[0].Elements);
  184. // 多边形(此item需在直线item添加之前添加)
  185. parserData.zoneLegendList.forEach(t => {
  186. this.scene.addItem(t);
  187. // 记录提取
  188. if (t.data.Properties && t.data.Properties.FID) {
  189. this.scene.fidToItem[t.data.Properties.FID].isExtracted = true;
  190. }
  191. this.scene.Nodes.push(t);
  192. itemMap[t.id] = t;
  193. });
  194. // 增加文字(此item需在直线item添加之前添加)
  195. parserData.textMarkerList.forEach(t => {
  196. this.scene.addItem(t);
  197. this.scene.Markers.push(t);
  198. itemMap[t.id] = t;
  199. });
  200. // 增加图片(此item需在直线item添加之前添加)
  201. parserData.imageMarkerList.forEach(t => {
  202. this.scene.addItem(t);
  203. this.scene.Markers.push(t);
  204. itemMap[t.id] = t;
  205. });
  206. // 增加图标类图例(此item需在管线item添加之前添加)
  207. parserData.imageLegendList.forEach(t => {
  208. this.scene.addItem(t);
  209. this.scene.Nodes.push(t);
  210. if (t.anchorList && t.anchorList.length) {
  211. t.anchorList.forEach(anc => {
  212. itemMap[anc.id] = anc;
  213. });
  214. }
  215. });
  216. // 增加直线
  217. parserData.lineMarkerList.forEach(t => {
  218. this.scene.addItem(t);
  219. this.scene.Markers.push(t);
  220. // 设置关联Item
  221. if (t.data.Properties && t.data.Properties.StartItemId) {
  222. const startItem = itemMap[t.data.Properties.StartItemId];
  223. startItem?.connect("onMove", t, t.changePos);
  224. t.startItem = startItem || null;
  225. }
  226. if (t.data.Properties && t.data.Properties.EndItemId) {
  227. const endItem = itemMap[t.data.Properties.EndItemId];
  228. endItem?.connect("onMove", t, t.changePos);
  229. t.endItem = endItem || null;
  230. }
  231. });
  232. // 增加管线类(需在图标类图例添加后添加)
  233. parserData.relationList.forEach(t => {
  234. this.scene.addItem(t);
  235. this.scene.Relations.push(t);
  236. // 设置锚点
  237. if (t.anchor1ID) {
  238. const startAnc = itemMap[t.anchor1ID];
  239. startAnc.isConnected = true;
  240. startAnc.parent?.connect("changePos", t, t.changePos);
  241. t.startAnchor = startAnc || null;
  242. }
  243. if (t.anchor2ID) {
  244. const endAnc = itemMap[t.anchor2ID];
  245. endAnc.isConnected = true;
  246. endAnc.parent?.connect("changePos", t, t.changePos);
  247. t.endAnchor = endAnc || null;
  248. }
  249. });
  250. this.view.fitSceneToView();
  251. bus.$emit("elementDataChange", this.scene);
  252. }
  253. });
  254. },
  255. // 监听变化
  256. emitChange(itemMsg) {
  257. this.chiceItemList = itemMsg.itemList;
  258. this.$emit("changeFocusItem", itemMsg);
  259. bus.$emit("FocusItemChanged", itemMsg);
  260. },
  261. // 监听场景元素数据变化
  262. scenceUpdate(scence) {
  263. bus.$emit("elementDataChange", scence);
  264. },
  265. clearGraphy() {
  266. if (this.view) {
  267. this.view.scene = null;
  268. return;
  269. }
  270. this.view = new FloorView("canvas");
  271. document.getElementById("canvas").focus();
  272. },
  273. getBus() {
  274. bus.$on("changeText", val => {
  275. this.scene.updatedText(val);
  276. });
  277. bus.$on("changeFont", val => {
  278. this.scene.updatedFontSize(val);
  279. });
  280. bus.$on("changeLineWidth", val => {
  281. this.scene.updatedLineWidth(val);
  282. });
  283. bus.$on("changeBorderColor", val => {
  284. this.scene.updatedBorderColor(val);
  285. });
  286. bus.$on("changeFontColor", val => {
  287. this.scene.updatedFontColor(val);
  288. });
  289. bus.$on("itemWidth", val => {
  290. this.scene.updatedWidth(Number(val));
  291. });
  292. bus.$on("itemHeight", val => {
  293. this.scene.updatedHeight(Number(val));
  294. });
  295. bus.$on("itemPositon", (x, y) => {
  296. this.scene.updatedPosition(Number(x), Number(y));
  297. });
  298. bus.$on("changebackColor", val => {
  299. this.scene.updatedbackColor(val);
  300. });
  301. bus.$on("deleiteItem", () => {
  302. this.scene.deleiteItem();
  303. });
  304. bus.$on("changeAlignItem", val => {
  305. this.scene.changeAlignItem(val);
  306. });
  307. bus.$on("extractItem", () => {
  308. const map = {};
  309. this.fParser.spaceList.forEach(t => {
  310. if (this.hasTypeList.indexOf(t.data.Type) > -1) {
  311. if (map[t.data.Type]) {
  312. map[t.data.Type]++;
  313. } else {
  314. map[t.data.Type] = 1;
  315. }
  316. }
  317. });
  318. const data = [];
  319. for (const key in map) {
  320. data.push({
  321. key: key,
  322. name: key,
  323. age: "",
  324. number: map[key],
  325. address: "提取"
  326. });
  327. }
  328. bus.$emit("exportItem", data);
  329. });
  330. bus.$on("saveMsgItem", () => {
  331. this.saveMsg()
  332. });
  333. bus.$on("exportByKey", val => {
  334. const list = this.fParser.spaceList
  335. .map(t => {
  336. if (t.data.Type == val.key) {
  337. if (!t.isExtracted) {
  338. t.isExtracted = true;
  339. return {
  340. ID: uuid(),
  341. Name: val.name,
  342. GraphElementType: val.properties.Type,
  343. GraphElementId: "273d633cc5c54a4882794b34843d1a00",
  344. AttachObjectIds: [],
  345. Pos: { x: t.x, y: t.y },
  346. OutLine: t.pointArr[0],
  347. SubType: "",
  348. Properties: {
  349. StrokeColor: "#3d73c0",
  350. FillColor: "#72f5f980",
  351. font: 0,
  352. color: "",
  353. TextPos: { X: 0, Y: 0 }
  354. },
  355. Num: 1
  356. };
  357. }
  358. }
  359. })
  360. .filter(item => item);
  361. const parserData = new STopologyParser(null);
  362. parserData.parseData({ Nodes: list });
  363. parserData.zoneLegendList.forEach(t => {
  364. this.scene.addItem(t);
  365. this.scene.Nodes.push(t);
  366. });
  367. // undo/redo事件
  368. this.scene.AddListCommand(parserData.zoneLegendList)
  369. });
  370. // 设备图例样式对象
  371. bus.$on("setLenged", obj => {
  372. this.scene.setlegend = obj;
  373. });
  374. // 修改图片url
  375. bus.$on("upadataImageUrl", val => {
  376. this.scene.upadataImageUrl(val);
  377. });
  378. // 改变边框样式
  379. bus.$on("changeBorder", val => {
  380. this.scene.upadataBorder(val);
  381. });
  382. // 改变图例名称
  383. bus.$on("changeLengedName", val => {
  384. this.scene.upadataLengedName(val);
  385. });
  386. // 改变图例名称
  387. bus.$on("changeImageNum", val => {
  388. this.scene.upadatImageNum(val);
  389. });
  390. // 修改填充色
  391. bus.$on("changefillColor", val => {
  392. this.scene.upadatfillColor(val);
  393. });
  394. // 修改当前得状态是否为编辑状态
  395. bus.$on("OpenEditStatus", () => {
  396. ` `; // 获取焦点item (必须选中且仅选中一个)
  397. if (
  398. this.chiceItemList &&
  399. this.chiceItemList.length &&
  400. this.chiceItemList.length == 1
  401. ) {
  402. if (this.scene.grabItem) {
  403. this.view.tryDbclick();
  404. } else {
  405. this.scene.grabItem = this.chiceItemList[0];
  406. this.view.tryDbclick();
  407. }
  408. }
  409. });
  410. //修改图例说明
  411. bus.$on("changeitemExplain", val => {
  412. this.scene.upadatitemExplain(val);
  413. });
  414. //发布图
  415. bus.$on("publishGraph", val => {
  416. publishGraph({ graphId: this.graphId, pubUser: "" }).then(res => {
  417. if (res.Result == "success") {
  418. this.$message.success(res.Message);
  419. } else {
  420. this.$message.error(res.Message);
  421. }
  422. });
  423. });
  424. //创建区域是否点选
  425. bus.$on("changeDrawType", val => {
  426. this.scene.isSelecting = val == "select";
  427. }),
  428. //发布图
  429. bus.$on("publishMap", () => {
  430. if (this.graphId == "") {
  431. this.$message.error("请先保存");
  432. // 如果没有保存则先保存
  433. bus.$emit("saveMsgItem");
  434. return false;
  435. }
  436. this.publishBtn();
  437. });
  438. /**
  439. * @name changeScale缩放底图
  440. * @param { Number } zoom 缩放比例
  441. *
  442. */
  443. // TODO: changeScale缩放底图
  444. bus.$on("changeScale", zoom => {
  445. const { scale } = this.view;
  446. this.changeScaleByClick = true;
  447. this.view.scaleByPoint(
  448. zoom,
  449. this.canvasWidth / 2,
  450. this.canvasHeight / 2
  451. );
  452. this.changeScaleByClick = false;
  453. setTimeout(() => {}, 100);
  454. });
  455. // 更改图例数据工程化数据
  456. bus.$on("changeAttachObjectIds", arr => {
  457. this.scene.upadatAttachObjectIds(arr);
  458. });
  459. // redo
  460. bus.$on("changeRedo", () => {
  461. this.scene.redo();
  462. });
  463. // uodo/
  464. bus.$on("changeUndo", () => {
  465. this.scene.undo();
  466. });
  467. },
  468. // 读取数据
  469. readGroup() {
  470. const data = {
  471. categoryId: this.urlMsg.categoryId,
  472. projectId: this.urlMsg.projectId,
  473. BuildingID: this.urlMsg.BuildingID, // 建筑ID
  474. FloorID: this.urlMsg.FloorID // 楼层id
  475. };
  476. return readGroup(data);
  477. },
  478. //发布
  479. publishBtn() {
  480. console.log(this.graphId);
  481. const loadings = Loading.service({
  482. lock: true,
  483. text: "Loading",
  484. spinner: "el-icon-loading",
  485. background: "rgba(0, 0, 0, 0.7)"
  486. });
  487. const data = {
  488. BuildingID: this.urlMsg.BuildingID,
  489. CategoryID: this.urlMsg.categoryId,
  490. FloorID: this.urlMsg.FloorID,
  491. GraphId: this.graphId,
  492. ProjectID: this.urlMsg.projectId,
  493. PubUser: ""
  494. };
  495. publishGraph(data).then(res => {
  496. loadings.close();
  497. if (res.Result == "success") {
  498. this.$message.success("发布成功");
  499. setTimeout(() => {
  500. const data = `categoryId=${this.urlMsg.categoryId}&projectId=${this.urlMsg.projectId}&BuildingID=${this.urlMsg.BuildingID}&FloorID=${this.urlMsg.FloorID}&fmapID=${this.urlMsg.fmapID}`;
  501. const url =
  502. window.location.origin +
  503. "/wandaEditer/drafts?" +
  504. encodeURIComponent(data);
  505. window.open(url, true);
  506. }, 1000);
  507. } else {
  508. this.$message.error(res.Message);
  509. }
  510. });
  511. },
  512. // 获取typeid
  513. getTypeId() {
  514. const data = {
  515. categoryId: this.urlMsg.categoryId
  516. };
  517. queryTypeGraph(data).then(res => {
  518. this.hasTypeList = res.Data.map(t => Number(t));
  519. });
  520. },
  521. saveMsg() {
  522. const Elements = this.scene.saveMsgItem();
  523. const Seq = Number(this.urlMsg.seq);
  524. const data = {
  525. Elements,
  526. Name: this.appName, // 名称
  527. CategoryId: this.urlMsg.categoryId,
  528. ProjectID: this.urlMsg.projectId, // 项目ID
  529. BuildingID: this.urlMsg.BuildingID, // 建筑ID
  530. FloorID: this.urlMsg.FloorID, // 楼层id
  531. Seq // 楼层id
  532. };
  533. Message({
  534. message: "保存中,切勿关闭窗口!",
  535. type: "warning"
  536. });
  537. saveGroup(data)
  538. .then(res => {
  539. Message.close();
  540. this.graphId = res.Data;
  541. })
  542. .catch(err => {
  543. Message({
  544. message: "保存失败!",
  545. type: "error"
  546. });
  547. });
  548. }
  549. },
  550. watch: {
  551. cmdType: {
  552. handler(cmd) {
  553. if (cmd == null || cmd == "") {
  554. cmd = "choice";
  555. }
  556. this.scene.setCmd = cmd;
  557. },
  558. deep: true
  559. },
  560. "scene.cmd": {
  561. handler(cmd) {
  562. this.$emit("setCmdType", cmd);
  563. },
  564. deep: true
  565. },
  566. // 监听scale的变化
  567. "view.scale": {
  568. handler(scale) {
  569. // 滚轮触发的缩放
  570. if (!this.changeScaleByClick) {
  571. bus.$emit("mouseScale", scale / this.initScale);
  572. }
  573. }
  574. }
  575. },
  576. created() {
  577. const href = window.location.href;
  578. // 路由
  579. // const route = href.split("?")[0];
  580. // 参数处理
  581. let params = href.split("?")[1];
  582. if (!params) {
  583. // 参数有问题
  584. return false;
  585. }
  586. params = decodeURIComponent(params);
  587. // params = "categoryId=NTXT&ProjectID=5&BuildingID=1&FloorID=1"; // mock 参数
  588. const paramsArr = params.split("&");
  589. console.log("paramsArr", paramsArr);
  590. const obj = {};
  591. paramsArr.map(item => {
  592. const arr = item.split("=");
  593. obj[arr[0]] = arr[1];
  594. });
  595. this.urlMsg = obj;
  596. }
  597. };
  598. </script>
  599. <style lang="less" scoped>
  600. #baseEditer {
  601. background: #f7f9fa;
  602. width: 100%;
  603. height: 100%;
  604. // overflow: hidden;
  605. // position: relative;
  606. #fengMap {
  607. position: absolute;
  608. width: 100px;
  609. height: 100px;
  610. z-index: -1;
  611. }
  612. .canvas-container {
  613. width: 100%;
  614. height: 100%;
  615. }
  616. }
  617. </style>