|
@@ -0,0 +1,364 @@
|
|
|
+<!-- 画板 -->
|
|
|
+<template>
|
|
|
+ <div ref="baseMap" class="base-map">
|
|
|
+ <canvas
|
|
|
+ id="floorMap"
|
|
|
+ :width="canvasWidth"
|
|
|
+ :height="canvasHeight"
|
|
|
+ tabindex="0"
|
|
|
+ ></canvas>
|
|
|
+ </div>
|
|
|
+</template>
|
|
|
+<script>
|
|
|
+import { SGraphScene } from "@persagy-web/graph/lib";
|
|
|
+import { SGraphView, SGraphSvgItem } from "@persagy-web/graph";
|
|
|
+import { SFloorParser, getJsonz } from "@persagy-web/big/lib";
|
|
|
+import { SZoneParser } from "@persagy-web/big";
|
|
|
+
|
|
|
+export default {
|
|
|
+ props: {
|
|
|
+ // 是否展示大小控制器
|
|
|
+ hasShowContro: {
|
|
|
+ type: Boolean,
|
|
|
+ default: true,
|
|
|
+ required: false,
|
|
|
+ },
|
|
|
+ // //// 关于底图
|
|
|
+
|
|
|
+ // 一,展示底图的元素
|
|
|
+ // 3.是否展示柱子
|
|
|
+ isShowColumn: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false,
|
|
|
+ required: false,
|
|
|
+ },
|
|
|
+ // 4.是否展示墙
|
|
|
+ isShowWall: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false,
|
|
|
+ required: false,
|
|
|
+ },
|
|
|
+ // 5.是否展示虚拟墙
|
|
|
+ isShowVirtualWall: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false,
|
|
|
+ required: false,
|
|
|
+ },
|
|
|
+ // 6.是否展示门
|
|
|
+ isShowDoor: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false,
|
|
|
+ required: false,
|
|
|
+ },
|
|
|
+ // 7.是否展窗户
|
|
|
+ isShowWindow: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false,
|
|
|
+ required: false,
|
|
|
+ },
|
|
|
+ // 8.是否显示空间
|
|
|
+ isSpaceSelectable: {
|
|
|
+ type: Boolean,
|
|
|
+ default: true,
|
|
|
+ required: false,
|
|
|
+ },
|
|
|
+ // 是否展示底图名称
|
|
|
+ showBaseName: {
|
|
|
+ type: Boolean,
|
|
|
+ default: false,
|
|
|
+ required: false,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ data() {
|
|
|
+ return {
|
|
|
+ canvasWidth: 0, // 画布的宽
|
|
|
+ canvasHeight: 0, // 画布的高
|
|
|
+ view: null, // 视图 view
|
|
|
+ scene: null, // 场景类
|
|
|
+ };
|
|
|
+ },
|
|
|
+ methods: {
|
|
|
+ // 初始化
|
|
|
+ init() {
|
|
|
+ this.clearImg();
|
|
|
+ this.view ? (this.view.scene = this.scene) : null;
|
|
|
+ // 获取压缩包数据并解压
|
|
|
+ this.getMapBlob();
|
|
|
+ },
|
|
|
+ // 选中图例
|
|
|
+ emitChoice(itemList) {
|
|
|
+ this.$emit("emitChoice", itemList);
|
|
|
+ this.choiceListLength = itemList.length;
|
|
|
+ },
|
|
|
+ // 鼠标点击画板事件
|
|
|
+ vueOnMouseDown(e) {
|
|
|
+ // 如果为非拖动操作方可执行点击事件
|
|
|
+ if (!this.view.isDrag) {
|
|
|
+ this.$emit("vueOnMouseDown", e);
|
|
|
+ // 是否需要打点(必须在空间内)
|
|
|
+ // setTimeout 用于让选中事件先于vue 点击
|
|
|
+ setTimeout(() => {
|
|
|
+ if (this.choiceListLength) {
|
|
|
+ if (
|
|
|
+ (typeof this.SetNewMarkConfig == "boolean" &&
|
|
|
+ this.SetNewMarkConfig == true) ||
|
|
|
+ typeof this.SetNewMarkConfig == "object"
|
|
|
+ ) {
|
|
|
+ this.setNewMark(e, this.SetNewMarkConfig);
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }, 100);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 请求获取地图的压缩包
|
|
|
+ getMapBlob() {
|
|
|
+ const url = this.mapUrl + this.dataKey;
|
|
|
+ getJsonz(url).then((data) => {
|
|
|
+ // 解析数据并放入压缩包中
|
|
|
+ this.parserData(data);
|
|
|
+ });
|
|
|
+ },
|
|
|
+ // 解析数据并注入 scene 类中
|
|
|
+ parserData(data) {
|
|
|
+ let parser = new SFloorParser();
|
|
|
+ parser.parseData(data);
|
|
|
+ parser.spaceList.forEach((t) => {
|
|
|
+ //是否显示空间
|
|
|
+ t.visible = this.isSpaceSelectable;
|
|
|
+ //设置样式
|
|
|
+ t.style = this.baseMapStyle;
|
|
|
+ //是否展示名称
|
|
|
+ t.showBaseName = this.showBaseName;
|
|
|
+ // 是否可选
|
|
|
+ t.selectable = true;
|
|
|
+ t.connect("onMouseDown", this, this.clickSpaceItem);
|
|
|
+
|
|
|
+ // 添加图例
|
|
|
+ this.scene.addItem(t);
|
|
|
+ });
|
|
|
+ parser.wallList.forEach((t) => {
|
|
|
+ //是否显示
|
|
|
+ t.visible = this.isShowWall;
|
|
|
+ // 是否可选
|
|
|
+ t.selectable = true;
|
|
|
+ this.scene.addItem(t);
|
|
|
+ });
|
|
|
+ parser.virtualWallList.forEach((t) => {
|
|
|
+ //是否显示
|
|
|
+ t.visible = this.isShowVirtualWall;
|
|
|
+ // 是否可选
|
|
|
+ t.selectable = true;
|
|
|
+ this.scene.addItem(t);
|
|
|
+ });
|
|
|
+ parser.doorList.forEach((t) => {
|
|
|
+ //是否显示
|
|
|
+ t.visible = this.isShowDoor;
|
|
|
+ // 是否可选
|
|
|
+ t.selectable = true;
|
|
|
+ this.scene.addItem(t);
|
|
|
+ });
|
|
|
+ parser.columnList.forEach((t) => {
|
|
|
+ //是否显示
|
|
|
+ t.visible = this.isShowColumn;
|
|
|
+ // 是否可选
|
|
|
+ t.selectable = true;
|
|
|
+ this.scene.addItem(t);
|
|
|
+ });
|
|
|
+ parser.casementList.forEach((t) => {
|
|
|
+ //是否显示
|
|
|
+ t.visible = this.isShowWindow;
|
|
|
+ // 是否可选
|
|
|
+ t.selectable = true;
|
|
|
+ this.scene.addItem(t);
|
|
|
+ });
|
|
|
+ // 画板是否可拖动
|
|
|
+ this.view.DragMove = true;
|
|
|
+ this.view.fitSceneToView();
|
|
|
+ },
|
|
|
+ // 图片缩小
|
|
|
+ changeSize(isbiger) {
|
|
|
+ if (isbiger) {
|
|
|
+ this.view.scaleByPoint(
|
|
|
+ (this.view.scale * 1.1) / this.view.scale,
|
|
|
+ this.canvasWidth / 2,
|
|
|
+ this.canvasHeight / 2
|
|
|
+ );
|
|
|
+ } else {
|
|
|
+ this.view.scaleByPoint(
|
|
|
+ (this.view.scale * 0.9) / this.view.scale,
|
|
|
+ this.canvasWidth / 2,
|
|
|
+ this.canvasHeight / 2
|
|
|
+ );
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 鼠标移入
|
|
|
+ mouseEnter(item, e) {
|
|
|
+ if (item.data.ElementType == "Mark") {
|
|
|
+ item.status = "highlight";
|
|
|
+ }
|
|
|
+ this.$emit("mouseEnter", item, e);
|
|
|
+ },
|
|
|
+ // 鼠标移出
|
|
|
+ mouseLeave(item, e) {
|
|
|
+ if (item.data.ElementType == "Mark") {
|
|
|
+ item.status = "default";
|
|
|
+ }
|
|
|
+ this.$emit("mouseLeave", e, item);
|
|
|
+ },
|
|
|
+ // 点击item
|
|
|
+ clickSpaceItem(item, e) {
|
|
|
+ console.log(item, e);
|
|
|
+ this.$emit("clickSpaceItem", e, item);
|
|
|
+ },
|
|
|
+ // 点击item
|
|
|
+ clickEquipItem(item, e) {
|
|
|
+ this.$emit("clickEquipItem", e, item);
|
|
|
+ },
|
|
|
+
|
|
|
+ // 解析设备点
|
|
|
+ mapEquipment(val) {
|
|
|
+ this.scene ? this.scene.clearEquip() : "";
|
|
|
+ const EqParse = new EquipmentParser(new EquipmentFactory());
|
|
|
+ const markList = [];
|
|
|
+ val.forEach((item) => {
|
|
|
+ if (item.bimLocation) {
|
|
|
+ const arr = item.bimLocation.split(",");
|
|
|
+ const mark = {
|
|
|
+ Id: item.equipId,
|
|
|
+ ElementType: "Mark",
|
|
|
+ equipId: item.equipId,
|
|
|
+ Name: item.equipName,
|
|
|
+ x: Number(arr[0]),
|
|
|
+ y: Number(arr[1]),
|
|
|
+ width: item.width,
|
|
|
+ height: item.height,
|
|
|
+ imgSource: item.imgSource,
|
|
|
+ textObj: item.textObj ? item.textObj : null,
|
|
|
+ tooltipMsg: item.tooltipMsg || [],
|
|
|
+ };
|
|
|
+ markList.push(mark);
|
|
|
+ }
|
|
|
+ });
|
|
|
+ EqParse.parseData(markList);
|
|
|
+ EqParse.markList.forEach((item) => {
|
|
|
+ item.style = this.equipStyle;
|
|
|
+ item.status = "disabled"; // 更具状态展示不同的效果;
|
|
|
+ item.connect("mouseEnter", this, this.mouseEnter);
|
|
|
+ item.connect("mouseLeave", this, this.mouseLeave);
|
|
|
+ item.connect("click", this, this.clickEquipItem);
|
|
|
+
|
|
|
+ this.scene.addItem(item);
|
|
|
+ });
|
|
|
+ this.scene.equipItemList = EqParse.markList;
|
|
|
+ },
|
|
|
+ // 解析业务空间
|
|
|
+ mapSpace(val) {
|
|
|
+ this.scene ? this.scene.clearSpace() : "";
|
|
|
+ const parse = new SZoneParser();
|
|
|
+ parse.parseData(val);
|
|
|
+ parse.zoneList.forEach((item) => {
|
|
|
+ item.connect("click", this, this.clickSpaceItem);
|
|
|
+ this.scene.addItem(item);
|
|
|
+ });
|
|
|
+ this.scene.zoonItemList = parse.markList;
|
|
|
+ },
|
|
|
+ // 清空画布
|
|
|
+ clearImg() {
|
|
|
+ this.scene = new FloorScene();
|
|
|
+ this.scene.emitChoice = this.emitChoice;
|
|
|
+ this.scene.vueOnMouseDown = this.vueOnMouseDown;
|
|
|
+ if (this.view) {
|
|
|
+ this.view.update();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ // 打点操作
|
|
|
+ setNewMark(e, markConfig) {
|
|
|
+ let markWidth = 30;
|
|
|
+ let markHeight = 30;
|
|
|
+ // // 是否需要自定义mark
|
|
|
+ if (typeof markConfig == "object") {
|
|
|
+ markWidth = Number(markConfig.width) ? Number(markConfig.width) : 30;
|
|
|
+ markHeight = Number(markConfig.height) ? Number(markConfig.height) : 30;
|
|
|
+ }
|
|
|
+ let mark = null;
|
|
|
+ if (this.newMarkList.length) {
|
|
|
+ mark = this.newMarkList[0];
|
|
|
+ mark.x = e.x;
|
|
|
+ mark.y = e.y;
|
|
|
+ } else {
|
|
|
+ // 有且只有一个mark
|
|
|
+ const EqParse = new EquipmentParser(new EquipmentFactory());
|
|
|
+ mark = {
|
|
|
+ Id: new Date(),
|
|
|
+ Name: "",
|
|
|
+ width: markWidth,
|
|
|
+ height: markHeight,
|
|
|
+ x: e.x,
|
|
|
+ y: e.y,
|
|
|
+ };
|
|
|
+ EqParse.parseData([mark]);
|
|
|
+ EqParse.markList.forEach((item) => {
|
|
|
+ item.style = this.equipStyle;
|
|
|
+ this.scene.addItem(item);
|
|
|
+ this.newMarkList.push(item);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ this.$emit("setNewMark", e);
|
|
|
+ },
|
|
|
+ },
|
|
|
+ watch: {
|
|
|
+ // 监听空间数组
|
|
|
+ zoneList: {
|
|
|
+ handler(val) {
|
|
|
+ if (val && val.length) {
|
|
|
+ this.mapSpace(val);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ deep: true,
|
|
|
+ },
|
|
|
+ // 监听设备数组
|
|
|
+ equipmentList: {
|
|
|
+ handler(val) {
|
|
|
+ if (val && val.length) {
|
|
|
+ this.mapEquipment(val);
|
|
|
+ }
|
|
|
+ },
|
|
|
+ deep: true,
|
|
|
+ },
|
|
|
+ // 监听key
|
|
|
+ dataKey: {
|
|
|
+ handler(val) {
|
|
|
+ if (val) {
|
|
|
+ this.init();
|
|
|
+ }
|
|
|
+ },
|
|
|
+ immediate: true,
|
|
|
+ },
|
|
|
+ },
|
|
|
+ created() {
|
|
|
+ this.clearImg();
|
|
|
+ },
|
|
|
+ mounted() {
|
|
|
+ // 获取 canvas 的宽高
|
|
|
+ this.canvasWidth = this.$refs.baseMap.offsetWidth;
|
|
|
+ this.canvasHeight = this.$refs.baseMap.offsetHeight;
|
|
|
+ // 初始化场景类
|
|
|
+ this.view = new FloorView("floorMap");
|
|
|
+ if (this.scene) {
|
|
|
+ this.view.scene = this.scene;
|
|
|
+ }
|
|
|
+ },
|
|
|
+};
|
|
|
+</script>
|
|
|
+<style lang="less" scoped>
|
|
|
+.base-map {
|
|
|
+ width: 100%;
|
|
|
+ height: 100%;
|
|
|
+ position: relative;
|
|
|
+ .sacle-btn {
|
|
|
+ position: absolute;
|
|
|
+ right: 0;
|
|
|
+ bottom: 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+</style>
|