import * as zrUtil from 'zrender/src/core/util'; import zrender from 'zrender'; import localStore from 'storejs'; import Painter from './painter'; import Options from './options'; import MouseController from './mouseController'; import KeyboardController from './keyboardController'; import deviceState from './constant/deviceState'; // 初始化默认状态 import deviceType from './constant/deviceType'; import { selectLineCode } from './config/deviceStyle'; import { deviceFactory, createBoundingRect, calculateDCenter } from './utils/parser'; import { deepAssign } from '@/utils/index'; import store from '@/store'; const renderer = 'canvas'; const devicePixelRatio = 1; class Jlmap { constructor(opts) { // 回调事件 this.methods = opts.methods; // 鼠标事件 this.events = { __Pan: 'pan', __Zoom: 'zoom', Selected: 'selected', Contextmenu: 'contextmenu', DataZoom: 'dataZoom', Keyboard: 'keyboard'}; // 线路参数 this.lineCode = ''; // 皮肤风格 this.style = {}; // 设备数据 this.mapDevice = {}; // 默认状态 this.defaultStateDict = this.loadDefaultState(); this.initMapInstance(opts); } // 初始化属性有鼠标事件 缩放等 initMapInstance(opts) { const width = opts.dom.clientWidth; const height = opts.dom.clientHeight; this.zoomOnMouseWheel = opts.options.zoomOnMouseWheel; this.$zr = zrender.init(opts.dom, deepAssign({ renderer, devicePixelRatio, width, height }, opts.config)); this.$options = new Options(deepAssign({ 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.$zr.getWidth(), height: this.$zr.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); this.$keyboardController = new KeyboardController(this); this.$keyboardController.enable(); } loadStyle(lineCode) { return selectLineCode(lineCode); } loadDefaultState() { // 加载默认状态 const defaultStateDict = {}; zrUtil.each(Object.keys(deviceState), (type) => { defaultStateDict[type] = {}; zrUtil.each(Object.keys(deviceState[type] || {}), (state) => { defaultStateDict[type][state] = deviceState[type][state]; // 新版地图直接使用判断结果 }, this); }, this); return defaultStateDict; } setMap(map, mapDevice, routeData) { // 保存皮肤类型 if (map.skinVO) { this.lineCode = map.skinVO.code; this.$options.scaleRate = map.skinVO.scaling || 1; this.$options.offsetX = map.skinVO.origin ? map.skinVO.origin.x : 0; this.$options.offsetY = map.skinVO.origin ? map.skinVO.origin.y : 0; } // 更新视图大小 this.$painter.updateTransform({ scaleRate: this.$options.scaleRate, offsetX: this.$options.offsetX, offsetY: this.$options.offsetY }); // 解析后的数据 this.mapDevice = mapDevice; // 进路数据 this.routeData = routeData; // 加载对应皮肤 this.style = this.loadStyle(this.lineCode); // 数据加载完成 回调 if (this.methods.dataLoaded instanceof Function) { this.methods.dataLoaded(this.mapDevice); } // 初次渲染视图 this.$painter.repaint(this.mapDevice); // 视图加载完成 回调 if (this.methods.viewLoaded instanceof Function) { this.methods.viewLoaded(this.mapDevice); } } setMapDevice(mapDevice) { this.mapDevice = mapDevice; } setDefaultState() { const list = []; Object.values(this.mapDevice).forEach(elem => { const code = elem.code; const type = elem._type; // 列车不需要设置默认状态 type != deviceType.Train && list.push(Object.assign({ code, _type: type }, this.defaultStateDict[type])); }); 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 { opts['zoomOnMouseWheel'] = this.zoomOnMouseWheel; this.$mouseController.enable(opts); } if (this.methods.optionsUpdate instanceof Function) { this.methods.optionsUpdate(this.$options); } } setCenter(deviceCode) { const device = this.mapDevice[deviceCode]; if (device && device.instance) { var rect = createBoundingRect(device.instance); var dcenter = calculateDCenter(rect, { width: this.$zr.getWidth(), height: this.$zr.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.mapDevice[code] || deviceFactory(type, elem); const nDevice = deepAssign(oDevice || {}, elem); this.$painter.delete(oDevice); delete this.mapDevice[code]; if (!elem._dispose) { this.mapDevice[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 (oDevice[prop] != elem[prop]) { deepAssign(oDevice, elem); // 更新状态 return true; } } return false; } // 后处理 postHandle(list) { list.forEach(elem => { const code = elem.code; const type = elem._type; if (type == deviceType.Switch) { const item = this.mapDevice[code]; if (item) { const sectionA = this.mapDevice[item.sectionACode]; const sectionB = this.mapDevice[item.sectionBCode]; const sectionC = this.mapDevice[item.sectionCCode]; if (sectionA && sectionB && sectionC) { item['cutOff'] = sectionA.cutOff; item['sectionAstatus'] = sectionA.status; item['sectionBstatus'] = sectionB.status; item['sectionCstatus'] = sectionC.status; } } this.$painter.update(item); } if (type == deviceType.Section) { const item = this.mapDevice[code]; if (item) { const swch = this.mapDevice[item.relSwitchCode]; if (swch) { const sectionA = this.mapDevice[swch.sectionACode]; const sectionB = this.mapDevice[swch.sectionBCode]; const sectionC = this.mapDevice[swch.sectionCCode]; if (sectionA && sectionB && sectionC) { swch['cutOff'] = sectionA.cutOff; swch['sectionAstatus'] = sectionA.status; swch['sectionBstatus'] = sectionB.status; swch['sectionCstatus'] = sectionC.status; } this.$painter.update(swch); } } } }); } setUpdateMapDevice(list) { store.dispatch('map/updateMapDevice', list); (list || []).forEach(elem => { const code = elem.code; const type = elem._type; const oDevice = this.mapDevice[code] || deviceFactory(type, elem); this.hookHandle(oDevice, elem) }); } update(list) { this.setUpdateMapDevice(list || []); // 增加一个 前数据 处理 为了在区段中 获取全部的 道岔信息 (list || []).forEach(elem => { const code = elem.code; const type = elem._type; if (elem.deviceType === 'ROUTE') { // 处理进路数据状态 store.dispatch('map/updateRouteState', elem); const route = this.routeData[code]; const signalDevice = this.mapDevice[route.startSignalCode]; const signalStatus = {atsControl: elem.atsControl}; if (this.hookHandle(signalDevice, signalStatus)) { this.$painter.update(signalDevice); } } else { const oDevice = this.mapDevice[code] || deviceFactory(type, elem); if (elem.dispose) { this.$painter.delete(oDevice); } else { // if (this.hookHandle(oDevice, elem)) { this.$painter.update(oDevice); // } } } }); // 状态后处理 this.postHandle(list || []); if (this.methods.stateUpdate instanceof Function) { this.methods.stateUpdate(list); } } pullBack(payload) { if (payload.type === 'zoom') { const zrWidth = this.$zr.getWidth(); const zrHeight = this.$zr.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 || {}; } getZr() { return this.$zr; } getEvents() { return this.events; } getDeviceByCode(code) { return this.mapDevice[code]; } getShapeTipPoint(opts) { const device = this.mapDevice[opts.code]; if (device) { return this.$painter.getShapeTipPoint(device.instance, opts); } } resize(opt) { this.$zr.resize(opt); this.$painter.updateZrSize(opt); } refresh() { this.$painter.refresh(); } clearTrainView() { this.$painter.clearLevel(deviceType.Train); zrUtil.each(Object.values(this.mapDevice), device => { if (device._type == deviceType.Train) { device.instance = null; } }); } clear() { this.lineCode = ''; this.style = {}; this.mapDevice = {}; this.$painter.clear(); } dispose() { this.off(this.events.Pan, this.optionsHandler); this.off(this.events.Zoom, this.optionsHandler); this.clear(); this.$mouseController.dispose(); this.$keyboardController.dispose(); this.$zr && zrender.dispose(this.$zr); 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; case this.events.Keyboard: this.$keyboardController.on(this.events.Keyboard, cb, context); } } } 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; case this.events.Keyboard: this.$keyboardController.off(this.events.keyboard, cb); break; } } } renderCheckBox(model) { const type = model._type; const code = model.code; const oDevice = this.mapDevice[code] || deviceFactory(type, model); const nDevice = deviceFactory(type, Object.assign(oDevice.model || {}, model)); delete this.mapDevice[code]; this.$painter.delete(oDevice); if (!model._dispose) { this.mapDevice[code] = nDevice; this.$painter.add(nDevice); } } deleteCheckBox(code) { const oDevice = this.mapDevice[code]; if (oDevice) { delete this.mapDevice[code]; this.$painter.delete(oDevice); } } } export default Jlmap;