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 deviceState from './constant/deviceState'; import deviceType from './constant/deviceType'; import { selectSkinCode } from './config/deviceStyle'; import { deviceFactory, createBoundingRect, calculateDCenter } from './utils/parser'; 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'}; // 原始数据 this.data = {}; // 皮肤参数 this.skinCode = ''; // 皮肤风格 this.style = this.loadStyle(); // 设备数据 this.mapDevice = {}; // 默认状态 this.defaultStateDict = this.loadDefaultState(); this.initMapInstance(opts); } // 初始化属性有鼠标事件 缩放等 initMapInstance(opts) { const width = opts.dom.clientWidth; const height = opts.dom.clientHeight; this.$zr = 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.$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); } loadStyle(skinCode) { return selectSkinCode(skinCode); } 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(map, mapDevice) { // 保存皮肤类型 if (map.skinVO) { this.skinCode = map.skinVO.code; } // 保存原始数据 this.data = map; // 解析地图数据 this.mapDevice = mapDevice; // 加载对应皮肤 this.style = this.loadStyle(this.skinCode); // 数据加载完成 回调 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); } } 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 { 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); } } setLayerVisible(layer) { this.$painter.setLayerVisible(layer); } 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 = Object.assign(oDevice || {}, elem); this.dataSync(nDevice); this.$painter.delete(oDevice); 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 (elem[prop] != oDevice[prop]) { Object.assign(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); } } } }); } update(list) { (list || []).forEach(elem => { const code = elem.code; const type = elem._type; 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 || {}; } dataSync(model) { var prop = null; var type = model._type; var code = model.code; switch (type) { case deviceType.Link: prop = 'linkList'; break; case deviceType.Section: prop = 'sectionList'; break; case deviceType.Switch: prop = 'switchList'; break; case deviceType.Signal: prop = 'signalList'; break; case deviceType.Station: prop = 'stationList'; break; case deviceType.StationStand: prop = 'stationStandList'; break; case deviceType.StationControl: prop = 'stationControlList'; break; case deviceType.StationCounter: prop = 'stationCounterList'; break; case deviceType.ZcControl: prop = 'zcControlList'; break; case deviceType.StationDelayUnlock: prop = 'stationDelayUnlockList'; break; case deviceType.LcControl: prop = 'lcControlList'; break; case deviceType.LimitControl: prop = 'tempSpeedLimitList'; break; case deviceType.ImageControl: prop = 'imageControl'; break; case deviceType.Train: prop = 'trainList'; break; case deviceType.TrainWindow: prop = 'trainWindowList'; break; case deviceType.Line: prop = 'lineList'; break; case deviceType.Text: prop = 'textList'; 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.$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.skinCode = ''; 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.$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; } } } 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 Jlmap;