diff --git a/src/assets/ibp_images/ibp_bg.png b/src/assets/ibp_images/ibp_bg.png
new file mode 100644
index 000000000..ba2d03cbf
Binary files /dev/null and b/src/assets/ibp_images/ibp_bg.png differ
diff --git a/src/assets/ibp_images/red_button.png b/src/assets/ibp_images/red_button.png
new file mode 100644
index 000000000..4dbb2bc6a
Binary files /dev/null and b/src/assets/ibp_images/red_button.png differ
diff --git a/src/assets/ibp_images/red_button_on.png b/src/assets/ibp_images/red_button_on.png
new file mode 100644
index 000000000..bcd9f6dd2
Binary files /dev/null and b/src/assets/ibp_images/red_button_on.png differ
diff --git a/src/ibp/constant/deviceRender.js b/src/ibp/constant/deviceRender.js
new file mode 100644
index 000000000..f304fe19c
--- /dev/null
+++ b/src/ibp/constant/deviceRender.js
@@ -0,0 +1,44 @@
+import deviceType from './deviceType';
+
+const deviceRender = {};
+
+/** Text渲染配置*/
+deviceRender[deviceType.Text] = {
+ zlevel: 1
+};
+
+/** SquareButton渲染配置*/
+deviceRender[deviceType.SquareButton] = {
+ zlevel: 1
+};
+
+/** WarnButton渲染配置*/
+deviceRender[deviceType.WarnButton] = {
+ zlevel: 1
+};
+
+/** Arrow渲染配置*/
+deviceRender[deviceType.Arrow] = {
+ zlevel: 1
+};
+
+/** RotatingButton渲染配置*/
+deviceRender[deviceType.RotatingButton] = {
+ zlevel: 1
+};
+
+/** Tip渲染配置*/
+deviceRender[deviceType.Tip] = {
+ zlevel: 1
+};
+
+/** BackGround渲染配置*/
+deviceRender[deviceType.Background] = {
+ zlevel: 0
+};
+
+/** CircularLamp渲染配置 */
+deviceRender[deviceType.CircularLamp] = {
+ zlevel: 1
+};
+export default deviceRender;
diff --git a/src/ibp/constant/deviceType.js b/src/ibp/constant/deviceType.js
new file mode 100644
index 000000000..18fb9e2be
--- /dev/null
+++ b/src/ibp/constant/deviceType.js
@@ -0,0 +1,12 @@
+const deviceType = {
+ Text: 'Text',
+ SquareButton: 'SquareButton',
+ WarnButton: 'WarnButton',
+ Arrow: 'Arrow',
+ RotatingButton: 'RotatingButton',
+ Tip: 'Tip',
+ Background: 'Background',
+ CircularLamp: 'CircularLamp'
+};
+
+export default deviceType;
diff --git a/src/ibp/constant/ibpData.js b/src/ibp/constant/ibpData.js
new file mode 100644
index 000000000..656fc75cc
--- /dev/null
+++ b/src/ibp/constant/ibpData.js
@@ -0,0 +1,51 @@
+
+const ibpData = {
+ background: {
+ type: 'Background',
+ code: 'bg_0000'
+ },
+ arrowList: [
+ {
+ type: 'Arrow',
+ code: '1111_arrow',
+ point: {
+ x: 510,
+ y: 400
+ },
+ length: 488,
+ stroke: '#0000CD',
+ fill: '#0000CD',
+ lineWidth: 1,
+ direction: '上行',
+ stationstandDirection: '三桥方向'
+ },
+ {
+ type: 'Arrow',
+ code: '1222_arrow',
+ point: {
+ x: 510,
+ y: 200
+ },
+ length: 488,
+ stroke: '#0000CD',
+ fill: '#0000CD',
+ lineWidth: 1,
+ direction: '下行',
+ stationstandDirection: '车辆段方向'
+ }
+ ],
+ circularLampList: [
+ {
+ type: 'CircularLamp',
+ code: '1333_lamp',
+ point: {
+ x: 600,
+ y: 600
+ },
+ r: 40,
+ fillColor: '#332C22'
+ }
+ ]
+};
+
+export default ibpData;
diff --git a/src/ibp/ibpPan.js b/src/ibp/ibpPan.js
new file mode 100644
index 000000000..a09561fee
--- /dev/null
+++ b/src/ibp/ibpPan.js
@@ -0,0 +1,306 @@
+import zrender from 'zrender';
+import * as zrUtil from 'zrender/src/core/util';
+import localStore from 'storejs';
+import Options from './options';
+import MouseController from './mouseController';
+import Painter from './painter';
+import deviceState from '../jmap/constant/deviceState';
+import deviceType from './constant/deviceType';
+import {calculateDCenter, createBoundingRect, deviceFactory} from './utils/parser';
+
+const renderer = 'canvas';
+const devicePixelRatio = 1;
+
+class IbpPan {
+ constructor(opts) {
+ this.methods = opts.methods;
+
+ // 鼠标事件
+ this.events = { __Pan: 'pan', __Zoom: 'zoom', Selected: 'selected', Contextmenu: 'contextmenu', DataZoom: 'dataZoom'};
+
+ // 皮肤参数
+ // this.skinCode = '';
+
+ // 设备数据
+ this.ibpDevice = {};
+
+ // 默认状态
+ this.defaultStateDict = this.loadDefaultState();
+
+ this.initIbpPage(opts);
+ }
+ initIbpPage(opts) {
+ const width = opts.config.width;
+ const height = opts.config.height;
+ this.$ibpZr = zrender.init(opts.dom, Object.assign({ renderer, devicePixelRatio, width, height }, opts.config));
+ this.$options = new Options(Object.assign({ scaleRate: 1, offsetX: 0, offsetY: 0 }, opts.options || {}), (dataZoom) => { this.$mouseController.trigger(this.events.DataZoom, dataZoom); }); // 缩放
+
+ this.$painter = new Painter(this);
+ this.$painter.updateZrSize({width: this.$ibpZr.getWidth(), height: this.$ibpZr.getHeight()});
+ this.$painter.updateTransform(this.$options);
+
+ this.optionsHandler = this.setOptions.bind(this);
+
+ this.$mouseController = new MouseController(this);
+ this.$mouseController.enable();
+
+ this.$mouseController.on(this.events.__Pan, this.optionsHandler);
+ this.$mouseController.on(this.events.__Zoom, this.optionsHandler);
+
+ }
+ loadDefaultState() {
+ const defaultStateDict = {};
+
+ zrUtil.each(Object.keys(deviceState), (type) => {
+ defaultStateDict[type] = {};
+ zrUtil.each(Object.keys(deviceState[type] || {}), (state) => {
+ defaultStateDict[type][state] = deviceState[type][state].Default;
+ }, this);
+ }, this);
+
+ return defaultStateDict;
+ }
+ setMap(config, ibpDevice) {
+ // 保存皮肤类型
+ if (config.config) {
+ this.$options.scaleRate = config.scaling;
+ this.$options.offsetX = config.origin.x;
+ this.$options.offsetY = config.origin.y;
+ this.$painter.updateTransform({ scaleRate: config.scaling, offsetX: config.origin.x, offsetY: config.origin.y });
+ }
+
+ // 保存原始数据
+ this.data = config;
+
+ // 解析地图数据
+ this.ibpDevice = ibpDevice;
+
+ // 加载对应皮肤
+ // this.style = this.loadStyle(this.skinCode);
+
+ // 数据加载完成 回调
+ if (this.methods.dataLoaded instanceof Function) { this.methods.dataLoaded(this.ibpDevice); }
+
+ // 初次渲染视图
+ this.$painter.repaint(this.ibpDevice);
+
+ // 视图加载完成 回调
+ if (this.methods.viewLoaded instanceof Function) { this.methods.viewLoaded(this.ibpDevice); }
+
+ }
+
+ setDefaultState() {
+ const list = [];
+ this.update(list);
+ if (this.methods.stateLoaded instanceof Function) { this.methods.stateLoaded(list); }
+ }
+
+ setOptions(opts) {
+ const options = this.pullBack(opts);
+ this.$options.update(options);
+ this.$painter.updateTransform(this.$options);
+
+ if (this.$options.disabled == true) {
+ this.$mouseController.disable();
+ } else {
+ this.$mouseController.enable(opts);
+ }
+
+ if (this.methods.optionsUpdate instanceof Function) { this.methods.optionsUpdate(this.$options); }
+ }
+
+ setCenter(deviceCode) {
+ const device = this.ibpDevice[deviceCode];
+ if (device && device.instance) {
+ var rect = createBoundingRect(device.instance);
+ var dcenter = calculateDCenter(rect, { width: this.$ibpZr.getWidth(), height: this.$ibpZr.getHeight() });
+ this.setOptions(dcenter);
+ }
+ }
+
+ setLevelVisible(list) {
+ this.$painter.setLevelVisible(list);
+ }
+
+ render(list) {
+ (list || []).forEach(elem => {
+ const code = elem.code;
+ const type = elem._type;
+ const oDevice = this.ibpDevice[code] || deviceFactory(type, elem);
+ const nDevice = Object.assign(oDevice || {}, elem);
+ this.dataSync(nDevice);
+ this.$painter.delete(oDevice);
+ if (!elem._dispose) {
+ this.ibpDevice[code] = nDevice;
+ this.$painter.add(nDevice);
+ }
+ });
+
+ if (this.methods.viewUpdate instanceof Function) { this.methods.viewUpdate(list); }
+ }
+
+ // 中间处理
+ hookHandle(oDevice, elem) {
+ const code = elem.code;
+ const type = elem._type;
+ // 如果是延时计时,需要保存计数值到全局
+ if (type === deviceType.StationCounter) {
+ let val = '' + elem.val;
+ if (val === '0' || !elem.val) {
+ val = elem.val = localStore.get(code) || '0';
+ }
+
+ localStore(code, val);
+ }
+ for (var prop in elem) {
+ if (elem[prop] != oDevice[prop]) {
+ Object.assign(oDevice, elem);
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ update(list) {
+ (list || []).forEach(elem => {
+ const code = elem.code;
+ const oDevice = this.ibpDevice[code];
+ if (elem.dispose) {
+ this.$painter.delete(oDevice);
+ } else {
+ if (this.hookHandle(oDevice, elem)) {
+ this.$painter.update(oDevice);
+ }
+ }
+ });
+
+ if (this.methods.stateUpdate instanceof Function) { this.methods.stateUpdate(list); }
+ }
+
+ pullBack(payload) {
+ if (payload.type === 'zoom') {
+ const zrWidth = this.$ibpZr.getWidth();
+ const zrHeight = this.$ibpZr.getHeight();
+ const originX = payload.originX || zrWidth / 2;
+ const originY = payload.originY || zrHeight / 2;
+ const x = (this.$options.offsetX + originX) / this.$options.scaleRate;
+ const y = (this.$options.offsetY + originY) / this.$options.scaleRate;
+ const newScaleRate = this.$options.getScaleRate(payload.scale);
+ const dx = originX - (x * newScaleRate - this.$options.offsetX);
+ const dy = originY - (y * newScaleRate - this.$options.offsetY);
+ payload.dx = dx;
+ payload.dy = dy;
+ }
+
+ return payload || {};
+ }
+
+ dataSync(model) {
+ var prop = null;
+ var type = model._type;
+ var code = model.code;
+
+ switch (type) {
+ case deviceType.Link: prop = 'linkList'; break;
+ }
+
+ const list = this.data[prop] || [];
+ const idex = list.findIndex(elem => { return elem.code == code; });
+ if (list) {
+ if (model._dispose) {
+ idex >= 0 && list.splice(idex, 1);
+ } else {
+ const elem = list[idex];
+ if (elem) {
+ Object.keys(elem).forEach(key => {
+ elem[key] = model[key];
+ });
+ } else {
+ list.push(Object.assign({}, model));
+ }
+ }
+ }
+ }
+
+ getZr() {
+ return this.$ibpZr;
+ }
+
+ getEvents() {
+ return this.events;
+ }
+
+ getDeviceByCode(code) {
+ return this.ibpDevice[code];
+ }
+
+ getShapeTipPoint(opts) {
+ const device = this.ibpDevice[opts.code];
+ if (device) {
+ return this.$painter.getShapeTipPoint(device.instance, opts);
+ }
+ }
+
+ resize(opt) {
+ this.$ibpZr.resize(opt);
+ this.$painter.updateZrSize(opt);
+ }
+
+ refresh() {
+ this.$painter.refresh();
+ }
+
+ clear() {
+ this.skinCode = '';
+ this.style = {};
+ this.ibpDevice = {};
+ this.$painter.clear();
+ }
+
+ dispose() {
+ this.off(this.events.Pan, this.optionsHandler);
+ this.off(this.events.Zoom, this.optionsHandler);
+
+ this.clear();
+
+ this.$mouseController.dispose();
+ this.$ibpZr && zrender.dispose(this.$ibpZr);
+ this.$painter.dispose();
+ }
+
+ on(eventname, cb, context) {
+ const idx = Object.values(this.events).indexOf(eventname);
+ if (idx >= 0) {
+ switch (eventname) {
+ case this.events.Selected:
+ this.$mouseController.on(this.events.Selected, cb, context);
+ break;
+ case this.events.Contextmenu:
+ this.$mouseController.on(this.events.Contextmenu, cb, context);
+ break;
+ case this.events.DataZoom:
+ this.$mouseController.on(this.events.DataZoom, cb, context);
+ break;
+ }
+ }
+ }
+
+ off(eventname, cb) {
+ const idx = Object.values(this.events).indexOf(eventname);
+ if (idx >= 0) {
+ switch (eventname) {
+ case this.events.Selected:
+ this.$mouseController.off(this.events.Selected, cb);
+ break;
+ case this.events.Contextmenu:
+ this.$mouseController.off(this.events.Contextmenu, cb);
+ break;
+ case this.events.DataZoom:
+ this.$mouseController.off(this.events.DataZoom, cb);
+ break;
+ }
+ }
+ }
+}
+export default IbpPan;
diff --git a/src/ibp/mouseController.js b/src/ibp/mouseController.js
new file mode 100644
index 000000000..f061602c2
--- /dev/null
+++ b/src/ibp/mouseController.js
@@ -0,0 +1,201 @@
+import deviceType from './constant/deviceType';
+import Eventful from 'zrender/src/mixin/Eventful';
+import * as eventTool from 'zrender/src/core/event';
+import store from '@/store';
+
+class EventModel {
+ constructor(e) {
+ this.clientX = e.event.clientX;
+ this.clientY = e.event.clientY;
+
+ let view = e.target;
+ while (view) {
+ if (Object.values(deviceType).includes(view._type)) {
+ this.deviceCode = view._code;
+ this.deviceType = view._type;
+ break;
+ }
+
+ if (view._subType) {
+ this.subType = view._subType;
+ }
+ if (view._val) {
+ this.val = view._val;
+ }
+
+ view = view.parent;
+ }
+ }
+}
+
+class MouseController extends Eventful {
+ constructor(ibp) {
+ super();
+ this.$ibp = ibp;
+ this.$zr = ibp.getZr();
+ this.events = ibp.getEvents();
+ this.initHandler(this.$zr);
+ }
+
+ initHandler(zr) {
+ if (zr) {
+ zr.on('click', this.click, this);
+ zr.on('contextmenu', this.contextmenu, this);
+ zr.on('mousemove', this.moveEvent, this);
+
+ this.enable = function (opts) {
+ opts = opts || {};
+ this._moveOnMouseMove = opts.moveOnMouseMove || true;
+ this._zoomOnMouseWheel = opts.zoomOnMouseWheel || false;
+ this._preventDefaultMouseMove = opts.preventDefaultMouseMove || true;
+
+ this.disable();
+
+ zr.on('mousedown', this.mousedown, this);
+ zr.on('mousemove', this.mousemove, this);
+ zr.on('mouseup', this.mouseup, this);
+ zr.on('mousewheel', this.mousewheel, this);
+ };
+
+ this.disable = function () {
+ zr.off('mousedown', this.mousedown);
+ zr.off('mousemove', this.mousemove);
+ zr.off('mouseup', this.mouseup);
+ zr.off('mousewheel', this.mousewheel);
+ };
+
+ this.dispose = function () {
+ zr.off('click', this.click);
+ zr.off('contextmenu', this.contextmenu);
+ zr.off('mousemove', this.moveEvent);
+ this.disable();
+ };
+
+ this.isDragging = function () { return this._dragging; };
+ }
+ }
+
+ mousedown(e) {
+ if (eventTool.notLeftMouse(e)) {
+ return;
+ }
+
+ var x = e.offsetX;
+ var y = e.offsetY;
+
+ this._x = x;
+ this._y = y;
+ this._dragging = true;
+ }
+
+ mousemove(e) {
+ if (eventTool.notLeftMouse(e) ||
+ !this._moveOnMouseMove ||
+ !this._dragging
+ ) {
+ return;
+ }
+
+ const oldX = this._x;
+ const oldY = this._y;
+
+ const dx = e.offsetX - oldX;
+ const dy = e.offsetY - oldY;
+
+ this._x = e.offsetX;
+ this._y = e.offsetY;
+
+ this._preventDefaultMouseMove && eventTool.stop(e.event);
+
+ this.trigger(this.events.__Pan, { dx, dy, oldX, oldY, newX: this._x, newY: this._y });
+ }
+
+ mouseup(e) {
+ if (!eventTool.notLeftMouse(e)) {
+ this._dragging = false;
+ }
+ }
+
+ mousewheel(e) {
+ const shouldZoom = this._zoomOnMouseWheel;
+ const wheelDelta = e.wheelDelta;
+ const originX = e.offsetX;
+ const originY = e.offsetY;
+
+ if (wheelDelta === 0 || !shouldZoom) {
+ return;
+ }
+
+ if (shouldZoom) {
+ eventTool.stop(e.event);
+ let scale = 1;
+ if (wheelDelta > 0) {
+ scale = 1;
+ } else if (wheelDelta < 0) {
+ scale = -1;
+ }
+
+ this.trigger(this.events.__Zoom, {type: 'zoom', scale, originX, originY });
+ }
+ }
+
+ click(e) {
+ var em = this.checkEvent(e);
+ this.trigger(this.events.Selected, em);
+ }
+
+ contextmenu(e) {
+ var em = this.checkEvent(e);
+ this.trigger(this.events.Contextmenu, em);
+ }
+
+ moveEvent(e) {
+ const newEm = new EventModel(e);
+ const trainDetails = store.state.map.trainDetails;
+ if (trainDetails) {
+ if (newEm.deviceType != deviceType.Train || trainDetails.code != newEm.deviceCode) {
+ var instance = (this.$ibp.getDeviceByCode(trainDetails.code) || {} ).instance;
+ instance && instance.removeTrainDetail && instance.removeTrainDetail();
+ }
+ }
+ }
+
+ checkEvent(e) {
+ var oldEm = new EventModel(this.$zr.curEvent || { event: {} });
+ var newEm = new EventModel(e);
+ if ([1, 3].includes(e.which)) {
+ // 查找之前和当前鼠标选中的实例
+ var oldDevice = this.$ibp.getDeviceByCode(oldEm.deviceCode) || {};
+ var newDevice = this.$ibp.getDeviceByCode(newEm.deviceCode) || {};
+ var oldInstance = (this.$ibp.getDeviceByCode(oldEm.deviceCode) || {}).instance || {};
+ var newInstance = (this.$ibp.getDeviceByCode(newEm.deviceCode) || {}).instance || {};
+
+ // 如果之前和当前选中的实例不一致
+ if (oldInstance != newInstance) {
+ // 如果实例有取消选择函数并且被点击,则执行取消选中函数
+ if (oldInstance.mouseEvent && oldInstance.mouseEvent.mouseout) {
+ // 视图数据设置点击标志,同步执行
+ oldDevice['down'] = false;
+ oldInstance.mouseEvent['mouseout'](e);
+ }
+
+ // 如果实例有选中函数并且被点击,则执行选中函数
+ if (e.which == 3 && newInstance.mouseEvent && newInstance.mouseEvent.mouseover) {
+ newDevice['down'] = true;
+ newInstance.mouseEvent['mouseover'](e);
+ }
+ }
+
+ // 保存当前实例到全局
+ this.$zr.curEvent = e;
+ }
+
+ return newEm;
+ }
+
+ updateDatazoom(zoom) {
+ this.trigger(this.events.Datazoom, zoom);
+ }
+}
+
+export default MouseController;
diff --git a/src/ibp/options.js b/src/ibp/options.js
new file mode 100644
index 000000000..170db21ef
--- /dev/null
+++ b/src/ibp/options.js
@@ -0,0 +1,100 @@
+class Options {
+ constructor(opts, trigger) {
+ this.scaleIndex = 0;
+ this.scaleList = [
+ 0.5, 0.6, 0.7, 0.8, 0.9,
+ 1, 1.2, 1.4, 1.6, 1.8,
+ 2, 2.2, 2.4, 2.6, 2.8,
+ 3, 3.2, 3.4, 3.6, 3.8,
+ 4, 4.2, 4.4, 4.6, 4.8,
+ 5, 5.2, 5.4, 5.6, 5.8,
+ 6, 6.2, 6.4, 6.6, 6.8,
+ 7, 7.2, 7.4, 7.6, 7.8,
+ 8, 8.2, 8.4, 8.6, 8.8
+ ];
+
+ if (Number.isFinite(opts.scaleRate)) {
+ const idx = this.scaleList.indexOf(opts.scaleRate);
+ if (idx >= 0) {
+ this.scaleIndex = idx;
+ }
+ }
+
+ this.scaleRate = opts.scaleRate || this.scaleList[this.scaleIndex]; // 缩放比例
+
+ this.offsetX = opts.offsetX || 0; // x偏移
+
+ this.offsetY = opts.offsetY || 0; // y偏移
+
+ this.throttle = opts.throttle || 100; // 刷新频率
+
+ this.disabled = false;
+
+ this.moveOnMouseMove = true;
+
+ this.zoomOnMouseWheel = false;
+
+ this.preventDefaultMouseMove = true;
+
+ this.trigger = trigger;
+ }
+
+ update(payload) {
+ if (Number.isFinite(payload.dx)) {
+ this.offsetX -= payload.dx;
+ }
+ if (Number.isFinite(payload.dy)) {
+ this.offsetY -= payload.dy;
+ }
+
+ if (Number.isFinite(payload.offsetX)) {
+ this.offsetX = payload.offsetX;
+ }
+ if (Number.isFinite(payload.offsetY)) {
+ this.offsetY = payload.offsetY;
+ }
+
+ if (Number.isFinite(payload.scale)) {
+ if (Number.isFinite(payload.scale)) {
+ if ((this.scaleIndex + payload.scale) >= 0 && (this.scaleIndex + payload.scale) < this.scaleList.length) {
+ this.scaleIndex = this.scaleIndex + payload.scale;
+ }
+ }
+ this.scaleRate = this.scaleList[this.scaleIndex];
+ }
+
+ if (Number.isFinite(payload.scaleRate)) {
+ const idx = this.scaleList.indexOf(payload.scaleRate);
+ if (idx < 0) {
+ return;
+ }
+ this.scaleIndex = idx;
+ this.scaleRate = payload.scaleRate;
+ }
+
+ if (payload.disabled === true || payload.disabled === false) {
+ this.disabled = payload.disabled;
+ }
+
+ if (payload.moveOnMouseMove === true || payload.moveOnMouseMove === false) {
+ this.moveOnMouseMove = payload.moveOnMouseMove;
+ }
+
+ if (payload.zoomOnMouseWheel === true || payload.zoomOnMouseWheel === false) {
+ this.zoomOnMouseWheel = payload.zoomOnMouseWheel;
+ }
+
+ if (this.trigger instanceof Function) { this.trigger(this); }
+ }
+
+ getScaleRate(scale) {
+ if (Number.isFinite(scale)) {
+ if ((this.scaleIndex + scale) >= 0 && (this.scaleIndex + scale) < this.scaleList.length) {
+ return this.scaleList[this.scaleIndex + scale];
+ }
+ }
+ return this.scaleList[this.scaleIndex];
+ }
+}
+
+export default Options;
diff --git a/src/ibp/painter.js b/src/ibp/painter.js
new file mode 100644
index 000000000..532276e83
--- /dev/null
+++ b/src/ibp/painter.js
@@ -0,0 +1,194 @@
+import * as zrUtil from 'zrender/src/core/util';
+import * as vector from 'zrender/src/core/vector';
+import Group from 'zrender/src/container/Group';
+import deviceType from './constant/deviceType';
+import shapefactory from './shape/factory';
+import TransformHandle from './transformHandle';
+
+class Painter {
+ constructor(ibp) {
+ // 父级实例
+ this.$ibp = ibp;
+ this.$ibpZr = ibp.getZr();
+
+ // 图层数据
+ this.ibpInstanceLevel = {};
+
+ // 初始图层
+ this.initLevels();
+
+ // 视图控制器
+ this.$transformHandle = new TransformHandle(this);
+ }
+
+ /**
+ * 初始绘图实例
+ * @param {*} dom
+ * @param {*} config
+ */
+ initLevels() {
+
+ // 添加父级图层
+ this.parentLevel = new Group({ name: '__parent__' });
+ this.$ibpZr.add(this.parentLevel);
+
+ // 添加子级图层
+ zrUtil.each(Object.values(deviceType), (type) => {
+ const level = new Group({ name: `__${type}__` });
+ this.ibpInstanceLevel[type] = level;
+ this.parentLevel.add(level);
+ });
+ }
+
+ /**
+ * 重绘视图
+ * @param {*} ibpDevice
+ */
+ repaint(ibpDevice) {
+ // 清空视图
+ this.clear();
+
+ // 创建视图
+ Object.values(ibpDevice).forEach(device => {
+ this.add(device);
+ });
+ }
+
+ /**
+ * 添加视图
+ * @param {*} device
+ */
+ add(device) {
+ const instance = shapefactory(device, this.$ibp);
+ if (instance) {
+ device.instance = instance;
+ this.$transformHandle.transformView(instance);
+ this.ibpInstanceLevel[device._type].add(instance);
+ }
+ }
+
+ /**
+ * 删除视图
+ * @param {*} device
+ */
+ delete(device) {
+ const instance = device.instance;
+ if (instance) {
+ this.ibpInstanceLevel[device._type].remove(instance);
+ }
+ }
+
+ /**
+ * 更新视图
+ * @param {*} device
+ */
+ update(device) {
+ if (device) {
+ if (device._dispose) {
+ this.delete(device);
+ } else {
+ const instance = device.instance;
+ if (instance) {
+ instance.setState(device);
+ }
+ }
+ }
+ }
+
+ /**
+ * 更新transform变化
+ * @param {*} opt
+ */
+ updateTransform(opt,) {
+ this.$transformHandle.updateTransform(opt);
+ }
+
+ /**
+ * 更新zrender尺寸
+ * @param {*} opt
+ */
+ updateZrSize(opt) {
+ this.$transformHandle.updateZrSize(opt);
+ }
+
+ /**
+ * 过去坐标提示位置
+ * @param {*} opts
+ */
+ getShapeTipPoint(instance, opts) {
+ if (instance) {
+ var point = instance.getShapeTipPoint(opts);
+ if (point) {
+ // 矩阵变换
+ var transform = this.$transformHandle.transform;
+ var transPoint = vector.applyTransform([], [point.x, point.y], transform);
+ return {
+ x: transPoint[0],
+ y: transPoint[1]
+ };
+ }
+
+ }
+ }
+
+ /**
+ * 设置图层可见
+ * @param {*} code
+ */
+ setLevelVisible(list) {
+ zrUtil.each(Object.values(deviceType), type => {
+ const level = this.ibpInstanceLevel[type];
+ if (list.includes(type)) {
+ level.show();
+ } else {
+ level.hide();
+ }
+ }, this);
+ }
+
+ /**
+ * 刷新图层
+ */
+ refresh() {
+ this.$ibpZr.refresh();
+ }
+
+ /**
+ * 清除图层
+ */
+ clearLevel(type) {
+ const level = this.ibpInstanceLevel[type];
+ if (level) {
+ level.removeAll();
+ }
+ }
+
+ /**
+ * 清除canvas
+ */
+ clear() {
+ zrUtil.each(Object.values(this.ibpInstanceLevel), (level) => {
+ level && level.removeAll();
+ }, this);
+
+ this.refresh();
+ }
+
+ /**
+ * 销毁图层
+ */
+ dispose() {
+ this.ibpInstanceLevel = {};
+ this.parentLevel = null;
+ }
+
+ /**
+ * 父级图层
+ */
+ getParentLevel() {
+ return this.parentLevel;
+ }
+
+}
+
+export default Painter;
diff --git a/src/ibp/shape/arrow.js b/src/ibp/shape/arrow.js
new file mode 100644
index 000000000..00d133fba
--- /dev/null
+++ b/src/ibp/shape/arrow.js
@@ -0,0 +1,37 @@
+import Polygon from 'zrender/src/graphic/shape/Polygon';
+import Group from 'zrender/src/container/Group';
+import {arrow} from '../../jmap/shape/utils/ShapePoints';
+
+class Arrow extends Group {
+ constructor(model) {
+ super();
+ this.model = model;
+ this.create();
+ }
+
+ create() {
+ const model = this.model;
+ const point = arrow(this.model.point.x, this.model.point.y, this.model.length, 10);
+ this.arrow = new Polygon({
+ zlevel: model.zlevel,
+ z: model.z,
+ shape: {
+ points: point
+ },
+ style: {
+ stroke: model.stroke,
+ lineWidth: model.lineWidth,
+ fill: model.fill
+ }
+ });
+ this.add(this.arrow);
+ }
+
+ // 箭头颜色
+ setColor(color) {
+ this.arrow.setStyle('fill', color);
+ }
+
+}
+
+export default Arrow;
diff --git a/src/ibp/shape/background.js b/src/ibp/shape/background.js
new file mode 100644
index 000000000..dc75fb541
--- /dev/null
+++ b/src/ibp/shape/background.js
@@ -0,0 +1,50 @@
+import Group from 'zrender/src/container/Group';
+import Image from 'zrender/src/graphic/Image';
+import Rect from 'zrender/src/graphic/shape/Rect';
+import ibpBg from '@/assets/ibp_images/ibp_bg.png';
+
+export default class background extends Group {
+ constructor(model) {
+ super();
+ this.model = model;
+ this.zlevel = model.zlevel;
+ this.z = 1;
+ this.create();
+ }
+ create() {
+ this.imageBg = new Image({
+ zlevel: this.zlevel,
+ z: this.z,
+ style: {
+ x: 0,
+ y: 0,
+ image: ibpBg,
+ width: 2048,
+ height: 1024
+ }
+ });
+ this.tailorRect = new Rect({
+ zlevel: this.zlevel,
+ z: this.z,
+ shape: {
+ x: 0,
+ y: 0,
+ width: this.model.width,
+ height: this.model.height
+ }
+ });
+ this.tailorBgImage();
+ }
+ tailorBgImage() {
+ // this.imageBg.setClipPath(this.tailorRect);
+ this.add(this.imageBg);
+ }
+ setInitialPosition(opt) {
+ const x = this.imageBg.style.x;
+ const y = this.imageBg.style.y;
+ this.imageBg.setStyle('x', x-opt.offsetX);
+ this.imageBg.setStyle('y', y-opt.offsetY);
+ this.tailorRect.setShape('x', x-opt.offsetX);
+ this.tailorRect.setShape('y', y-opt.offsetY);
+ }
+}
diff --git a/src/ibp/shape/button.js b/src/ibp/shape/button.js
new file mode 100644
index 000000000..79bd902d0
--- /dev/null
+++ b/src/ibp/shape/button.js
@@ -0,0 +1,163 @@
+import Group from 'zrender/src/container/Group';
+import Image from 'zrender/src/graphic/Image';
+// import Eventful from 'zrender/src/mixin/Eventful';
+
+import * as eventTool from 'zrender/src/core/event';
+
+import buttonPic from '@/assets/ibp_images/red_button.png';
+import buttonPicOn from '@/assets/ibp_images/red_button_on.png';
+
+export default class button extends Group {
+ constructor(model) {
+ super();
+ this.model = model;
+ this.zlevel = model.zlevel;
+ this.z = model.z;
+ this.create();
+ this.createMouseEvent();
+ }
+ create() {
+ const model = this.model;
+ this.imageBg = new Image({
+ zlevel: this.zlevel,
+ z: this.z,
+ style: {
+ image: model.status === '01' ? buttonPic : buttonPicOn,
+ x: this.model.point.x,
+ y: this.model.point.y,
+ width: this.model.width,
+ height: this.model.height
+ }
+ });
+ this.add(this.imageBg);
+ }
+
+ // 设置按钮状态
+ setState(model) {
+ switch (model.status) {
+ case '01': this.close(); break; // 关闭
+ case '02': this.open(); break; // 开放
+ }
+ }
+
+ // 绑定按钮事件
+ createMouseEvent() {
+ this.model.isDraging=true;
+ if (this.model.isDraging) {
+ // 按钮拖拽事件监听
+ this.imageBg.on('mousedown', (e) => {
+ if (eventTool.notLeftMouse(e)) {
+ return;
+ }
+ eventTool.stop(e.event);
+ var x = e.offsetX;
+ var y = e.offsetY;
+ this._x = x;
+ this._y = y;
+ this._dragginger = true;
+ });
+ this.imageBg.on('mousemove', (e) => {
+ // !this._moveOnMouseMove ||
+ if (eventTool.notLeftMouse(e) || !this._dragginger) {
+ return;
+ }
+ // eventTool.stop(e.event);
+ const oldX = this._x;
+ const oldY = this._y;
+ const dx = e.offsetX - oldX;
+ const dy = e.offsetY - oldY;
+ this._x = e.offsetX;
+ this._y = e.offsetY;
+ debugger;
+ // this.imageBg.preventDefaultMouseMove &&
+ eventTool.stop(e.event);
+ // debugger;
+ this.imageBg.setStyle({x: oldX+dx, y: oldY+dy });
+ });
+
+ this.imageBg.on('mouseup', (e) => {
+ if (!eventTool.notLeftMouse(e)) {
+ this._dragginger = false;
+ }
+ });
+
+ } else {
+ // 按钮的点击监听
+ this.imageBg.on('click', (e) => {
+ switch (this.model.status) {
+ case '01': {
+ this.open();
+ this.model.status='02';
+ break;
+ }
+ case '02': {
+ this.close();
+ this.model.status='01';
+ break;
+ }
+ }
+ });
+ }
+ }
+
+// if (this.model.isDraging) {
+// // this.mouseEvent = new EMouse(this);
+// // this.add(this.mouseEvent);
+// this.imageBg.on('mousedown', (e) => {
+// // debugger;
+// if (eventTool.notLeftMouse(e)) {
+// return;
+// }
+// var x = e.offsetX;
+// var y = e.offsetY;
+// this._x = x;
+// this._y = y;
+// this._dragging = true;
+// });
+// this.imageBg.on('mousemove', (e) => {
+// if (eventTool.notLeftMouse(e) || !this._moveOnMouseMove ||!this._dragging) {
+// return;
+// }
+// const oldX = this._x;
+// const oldY = this._y;
+// const dx = e.offsetX - oldX;
+// const dy = e.offsetY - oldY;
+// this._x = e.offsetX;
+// this._y = e.offsetY;
+// debugger;
+// this.imageBg.preventDefaultMouseMove && eventTool.stop(e.event);
+// debugger;
+// this.imageBg.setStyle({x: dx, y: dy});
+// // this.trigger(this.events.__Pan, { dx, dy, oldX, oldY, newX: this._x, newY: this._y });
+
+// });
+// this.on('mouseup', (e) => { });
+// }
+// else {
+// this.on('mousedown', (e) => { this.mouseEvent.mouseout(e); });
+// // this.on('mousemove', (e) => { this.mouseEvent.mouseover(e); });
+// this.on('mouseup', (e) => { this.mouseEvent.mouseover(e); });
+// }
+
+ // 关闭
+ close() {
+ this.imageBg.setStyle({image: buttonPic});
+ }
+ // 开放
+ open() {
+ this.imageBg.setStyle({image: buttonPicOn});
+ }
+
+ getShapeTipPoint() {
+ if (this.imageBg) {
+ var distance = 2;
+ var rect = this.imageBg.getBoundingRect();
+ return {
+ x: rect.x + rect.width / 2,
+ y: rect.y - distance
+ };
+ }
+ return null;
+ }
+
+}
diff --git a/src/ibp/shape/circularLamp.js b/src/ibp/shape/circularLamp.js
new file mode 100644
index 000000000..38f6bc778
--- /dev/null
+++ b/src/ibp/shape/circularLamp.js
@@ -0,0 +1,33 @@
+import Group from 'zrender/src/container/Group';
+import Circle from 'zrender/src/graphic/shape/Circle';
+import MouseController from '../mouseController';
+
+export default class CircularLamp extends Group {
+ constructor(model) {
+ super();
+ this.model = model;
+ this.zlevel = model.zlevel;
+ this.z = model.z;
+ this.create();
+ }
+
+ create() {
+ this.lamp = new Circle({
+ zlevel: this.zlevel,
+ z: this.z,
+ shape: {
+ cx: this.model.point.x,
+ cy: this.model.point.y,
+ r: this.model.r
+ },
+ style: {
+ fill: this.model.fillColor
+ }
+ });
+ this.add(this.lamp);
+ }
+
+ setCircularLampColor(color) {
+ this.lamp.setStyle('fill', color);
+ }
+}
diff --git a/src/ibp/shape/element/textName.js b/src/ibp/shape/element/textName.js
new file mode 100644
index 000000000..fa743f051
--- /dev/null
+++ b/src/ibp/shape/element/textName.js
@@ -0,0 +1,25 @@
+// import Group from 'zrender/src/container/Group';
+import Text from 'zrender/src/graphic/Text';
+
+/** 名称元素*/
+export default function ETextName(model) {
+ const TextName = new Text({
+ zlevel: model.zlevel,
+ z: model.z,
+ silent: model.silent || false,
+ style: {
+ x: model.x,
+ y: model.y,
+ fontWeight: model.fontWeight,
+ fontSize: model.fontSize,
+ fontFamily: model.fontFamily,
+ text: model.text,
+ textStrokeWidth: model.textStrokeWidth,
+ textFill: model.textFill,
+ textAlign: model.textAlign,
+ textPosition: model.textPosition || 'inside',
+ textVerticalAlign: model.textVerticalAlign || null
+ }
+ });
+ return TextName;
+}
diff --git a/src/ibp/shape/factory.js b/src/ibp/shape/factory.js
new file mode 100644
index 000000000..3c9a1732a
--- /dev/null
+++ b/src/ibp/shape/factory.js
@@ -0,0 +1,20 @@
+import Arrow from './arrow';
+import deviceType from '../constant/deviceType';
+import Background from './background';
+import CircularLamp from './circularLamp'
+
+const ibpShape = {};
+ibpShape[deviceType.Arrow] = Arrow;
+ibpShape[deviceType.Background] = Background;
+ibpShape[deviceType.CircularLamp] = CircularLamp;
+
+function shapefactory(device, ibp) {
+ const type = device._type;
+ const shape = ibpShape[type];
+ if (shape instanceof Function) {
+ // eslint-disable-next-line
+ return new shape(device, ibp.style);
+ }
+}
+
+export default shapefactory;
diff --git a/src/ibp/transformHandle.js b/src/ibp/transformHandle.js
new file mode 100644
index 000000000..055aed10c
--- /dev/null
+++ b/src/ibp/transformHandle.js
@@ -0,0 +1,71 @@
+
+import {createTransform, createBoundingRect} from './utils/parser';
+
+class TransformHandle {
+ constructor(painter) {
+ this.$painter = painter;
+
+ this.parentLevel = painter.getParentLevel();
+
+ this.rect = { x: 0, y: 0, width: 0, height: 0 };
+
+ this.transform = createTransform({ scaleRate: 1, offsetX: 0, offsetY: 0 });
+ }
+
+ checkVisible(view) {
+ return createBoundingRect(view).intersect(this.rect);
+ }
+
+ revisibleView(view) {
+ if (this.checkVisible(view)) {
+ view.show();
+ } else {
+ view.hide();
+ }
+
+ view.dirty();
+ }
+
+ // 视图进行缩放/平移
+ transformView(view) {
+ if (view) {
+ view.transform = this.transform;
+ view.decomposeTransform();
+ this.revisibleView(view);
+ }
+ // return view;
+ }
+
+ // 处理所有视图缩放/平移
+ transformAll() {
+ this.traverse(this.transformView, this);
+ }
+
+ // 重新计算显示图形
+ revisibleAll() {
+ this.traverse(this.revisibleView, this);
+ }
+
+ // 更新偏移量
+ updateTransform(opts) {
+ this.transform = createTransform(opts);
+ this.transformAll();
+ }
+
+ // 更新画布尺寸
+ updateZrSize(opts) {
+ this.rect = { x: 0, y: 0, width: opts.width, height: opts.height };
+ this.revisibleAll();
+ }
+
+ // 遍历group执行回调
+ traverse(cb, context) {
+ this.parentLevel.eachChild(level => {
+ level.eachChild((view) => {
+ cb.call(context, view);
+ }, context);
+ }, context);
+ }
+}
+
+export default TransformHandle;
diff --git a/src/ibp/utils/parser.js b/src/ibp/utils/parser.js
new file mode 100644
index 000000000..049c8b137
--- /dev/null
+++ b/src/ibp/utils/parser.js
@@ -0,0 +1,78 @@
+import * as zrUtil from 'zrender/src/core/util';
+import * as matrix from 'zrender/src/core/matrix';
+import deviceType from '../constant/deviceType';
+import deviceRender from '../constant/deviceRender';
+
+export function createTransform(opts) {
+ let transform = matrix.create();
+ transform = matrix.scale(matrix.create(), transform, [opts.scaleRate, opts.scaleRate]);
+ transform = matrix.translate(matrix.create(), transform, [-opts.offsetX, -opts.offsetY]);
+ return transform;
+}
+
+export function createBoundingRect(view) {
+ const rect = view.getBoundingRect();
+ const scale = view.scale[0];
+ const offsetX = view.position[0];
+ const offsetY = view.position[1];
+ rect.x = rect.x * scale + offsetX;
+ rect.y = rect.y * scale + offsetY;
+ rect.width = rect.width * scale;
+ rect.height = rect.height * scale;
+ return rect;
+}
+
+export function calculateDCenter(viewRect, zrbound) {
+ var dx = (zrbound.width - viewRect.width) / 2 - viewRect.x;
+ var dy = 0;
+ return { dx: dx, dy: dy };
+}
+
+export function deviceFactory(type, elem) {
+ return Object.assign({ _type: type }, deviceRender[type], elem);
+}
+
+export function createDevice(type, model, propConvert) {
+ const device = deviceFactory(type, model);
+ return propConvert ? propConvert.initPrivateProps(device) : device;
+}
+
+export function parser(data, config) {
+ var ibpDevice = {};
+ const propConvert = null;
+ // var propConvert = skinCode ? Vue.prototype.$theme.loadPropConvert(skinCode): null;
+ if (data) {
+
+ Object.assign(data.background, config);
+ ibpDevice[data.background.code] = createDevice(deviceType.Background, data.background, propConvert);
+ zrUtil.each(data.textList || [], elem => {
+ ibpDevice[elem.code] = createDevice(deviceType.Text, elem, propConvert);
+ }, this);
+
+ zrUtil.each(data.squareButtonList || [], elem => {
+ ibpDevice[elem.code] = createDevice(deviceType.SquareButton, elem, propConvert);
+ }, this);
+
+ zrUtil.each(data.circularLampList || [], elem => {
+ ibpDevice[elem.code] = createDevice(deviceType.CircularLamp, elem, propConvert);
+ }, this);
+
+ zrUtil.each(data.warnButtonList || [], elem => {
+ ibpDevice[elem.code] = createDevice(deviceType.WarnButton, elem, propConvert);
+ }, this);
+
+ zrUtil.each(data.arrowList || [], elem => {
+ ibpDevice[elem.code] = createDevice(deviceType.Arrow, elem, propConvert);
+ }, this);
+
+ zrUtil.each(data.rotatingButtonList || [], elem => {
+ ibpDevice[elem.code] = createDevice(deviceType.RotatingButton, elem, propConvert);
+ }, this);
+
+ zrUtil.each(data.tipList || [], elem => {
+ ibpDevice[elem.code] = createDevice(deviceType.Tip, elem, propConvert);
+ }, this);
+ }
+
+ return ibpDevice;
+}
diff --git a/src/jmap/config/skinCode/chengdu_03.js b/src/jmap/config/skinCode/chengdu_03.js
index f7727888d..d127f42bd 100644
--- a/src/jmap/config/skinCode/chengdu_03.js
+++ b/src/jmap/config/skinCode/chengdu_03.js
@@ -27,7 +27,7 @@ class SkinCode extends defaultStyle {
textVerticalAlign: 'middle' // 文字垂直对齐方式
},
logicText: {
- show: false, // 逻辑区段名称显示
+ show: false, // 逻辑区段名称显示
position: 0, // 区段名称位置 1 上面 -1 下面 0 对称
distance: 12, // 文字离区段距离
fontSize: 11, // 字体大小
@@ -276,7 +276,7 @@ class SkinCode extends defaultStyle {
emergencyControlShow: true, // 紧急站控显示
centerControlShow: true, // 中控显示
substationControlShow: true, // 站控按钮显示
- turnedAroundControlShow: false // 按图折返显示
+ turnedAroundControlShow: true // 按图折返显示
},
arrow: {
show: false // 控制模式箭头显隐
diff --git a/src/utils/baseUrl.js b/src/utils/baseUrl.js
index 2e575c51e..b49dd28b5 100644
--- a/src/utils/baseUrl.js
+++ b/src/utils/baseUrl.js
@@ -4,7 +4,7 @@ export function getBaseUrl() {
if (process.env.NODE_ENV === 'development') {
// BASE_API = 'https://joylink.club/jlcloud';
BASE_API = 'https://test.joylink.club/jlcloud';
- // BASE_API = 'http://192.168.3.5:9000'; // 袁琪
+ // BASE_API = 'http://192.168.9.255:9000'; // 袁琪
// BASE_API = 'http://192.168.3.6:9000'; // 旭强
// BASE_API = 'http://192.168.3.4:9000' // 琰培
} else {
diff --git a/src/views/display/demon/addQuest.vue b/src/views/display/demon/addQuest.vue
index 0c2c146af..5d362c4bb 100644
--- a/src/views/display/demon/addQuest.vue
+++ b/src/views/display/demon/addQuest.vue
@@ -177,7 +177,10 @@ export default {
},
async confirm() {
+ await this.$store.dispatch('training/over');
+ await this.$store.dispatch('training/setMapDefaultState');
await this.$store.dispatch('map/clearJlmapTrainView');
+ await this.$store.dispatch('map/setTrainWindowShow', false);
this.$emit('selectQuest', this.row, this.form.role);
this.doClose();
this.roleDoClose();
diff --git a/src/views/display/index.vue b/src/views/display/index.vue
index 163787bfb..bb02ae19a 100644
--- a/src/views/display/index.vue
+++ b/src/views/display/index.vue
@@ -18,6 +18,7 @@
@tryTime="tryTime"
@hidepanel="hidepanel"
@quitQuest="quitQuest"
+ @showIbp="showIbp"
/>
课程说明:
+