rt-sim-training-client/src/jmap/map.js

412 lines
11 KiB
JavaScript
Raw Normal View History

2019-07-08 09:38:39 +08:00
import * as zrUtil from 'zrender/src/core/util';
2019-07-09 19:04:45 +08:00
import zrender from 'zrender';
2019-07-26 18:54:42 +08:00
import localStore from 'storejs';
2019-07-03 14:29:09 +08:00
import Painter from './painter';
2019-07-10 12:02:02 +08:00
import Options from './options';
2019-07-09 19:04:45 +08:00
import MouseController from './mouseController';
2019-07-16 13:34:03 +08:00
import deviceState from './constant/deviceState';
import deviceType from './constant/deviceType';
import { selectSkinCode } from './config/deviceStyle';
import { deviceFactory, createBoundingRect, calculateDCenter } from './utils/parser';
2019-07-03 14:29:09 +08:00
2019-07-09 19:04:45 +08:00
const renderer = 'canvas';
2019-07-22 15:43:42 +08:00
const devicePixelRatio = 1;
2019-07-09 19:04:45 +08:00
2019-07-25 10:32:29 +08:00
class Jlmap {
2019-07-04 10:59:40 +08:00
constructor(opts) {
2019-07-09 09:24:54 +08:00
// 回调事件
this.methods = opts.methods;
2019-07-10 12:02:02 +08:00
// 鼠标事件
2019-07-25 18:25:04 +08:00
this.events = { __Pan: 'pan', __Zoom: 'zoom', Selected: 'selected', Contextmenu: 'contextmenu', DataZoom: 'dataZoom'};
2019-07-10 12:02:02 +08:00
2019-07-04 10:59:40 +08:00
// 原始数据
this.data = {};
2019-07-03 14:29:09 +08:00
2019-07-04 10:59:40 +08:00
// 皮肤参数
2019-08-14 09:35:38 +08:00
this.skinCode = '';
2019-07-03 14:29:09 +08:00
2019-07-04 10:59:40 +08:00
// 皮肤风格
2019-07-30 16:47:11 +08:00
this.style = this.loadStyle();
2019-07-04 10:59:40 +08:00
// 设备数据
this.mapDevice = {};
2019-07-03 14:29:09 +08:00
2019-07-10 13:17:12 +08:00
// 默认状态
this.defaultStateDict = this.loadDefaultState();
2019-07-10 12:02:02 +08:00
this.initMapInstance(opts);
}
2019-07-11 17:58:58 +08:00
// 初始化属性有鼠标事件 缩放等
2019-07-10 12:02:02 +08:00
initMapInstance(opts) {
2019-07-11 17:58:58 +08:00
const width = opts.dom.clientWidth;
const height = opts.dom.clientHeight;
2019-07-10 12:02:02 +08:00
2019-07-10 13:17:12 +08:00
this.$zr = zrender.init(opts.dom, Object.assign({ renderer, devicePixelRatio, width, height }, opts.config));
2019-07-10 12:02:02 +08:00
2019-07-29 16:03:14 +08:00
this.$options = new Options(Object.assign({ scaleRate: 1, offsetX: 0, offsetY: 0 }, opts.options || {}), (dataZoom) => { this.$mouseController.trigger(this.events.DataZoom, dataZoom); }); // 缩放
2019-07-19 11:11:34 +08:00
this.$painter = new Painter(this);
2019-07-19 18:01:42 +08:00
this.$painter.updateZrSize({width: this.$zr.getWidth(), height: this.$zr.getHeight()});
2019-07-19 11:11:34 +08:00
this.$painter.updateTransform(this.$options);
2019-07-10 12:02:02 +08:00
2019-07-25 18:25:04 +08:00
this.optionsHandler = this.setOptions.bind(this);
2019-07-19 13:54:23 +08:00
2019-07-10 13:17:12 +08:00
this.$mouseController = new MouseController(this);
this.$mouseController.enable();
2019-07-10 12:02:02 +08:00
2019-07-25 18:25:04 +08:00
this.$mouseController.on(this.events.__Pan, this.optionsHandler);
this.$mouseController.on(this.events.__Zoom, this.optionsHandler);
2019-07-04 10:59:40 +08:00
}
2019-07-03 14:29:09 +08:00
2019-08-14 09:35:38 +08:00
loadStyle(skinCode) {
return selectSkinCode(skinCode);
2019-07-25 14:03:26 +08:00
}
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) {
2019-07-09 19:04:45 +08:00
// 保存皮肤类型
2019-07-25 18:25:04 +08:00
if (map.skinVO) {
2019-08-14 09:35:38 +08:00
this.skinCode = map.skinVO.code;
2019-08-21 17:34:08 +08:00
this.$options.scaleRate = map.skinVO.scaling;
this.$options.offsetX = map.skinVO.origin.x;
this.$options.offsetY = map.skinVO.origin.y;
this.$painter.updateTransform({ scaleRate: map.skinVO.scaling, offsetX: map.skinVO.origin.x, offsetY: map.skinVO.origin.y });
2019-07-25 18:25:04 +08:00
}
2019-07-09 19:04:45 +08:00
2019-07-04 10:59:40 +08:00
// 保存原始数据
2019-07-25 10:32:29 +08:00
this.data = map;
2019-07-04 10:59:40 +08:00
// 解析地图数据
this.mapDevice = mapDevice;
2019-07-18 18:25:57 +08:00
// 加载对应皮肤
2019-08-14 09:35:38 +08:00
this.style = this.loadStyle(this.skinCode);
2019-07-30 16:47:11 +08:00
2019-07-18 18:25:57 +08:00
// 数据加载完成 回调
2019-07-25 18:25:04 +08:00
if (this.methods.dataLoaded instanceof Function) { this.methods.dataLoaded(this.mapDevice); }
2019-07-08 09:38:39 +08:00
2019-07-04 10:59:40 +08:00
// 初次渲染视图
2019-07-18 18:25:57 +08:00
this.$painter.repaint(this.mapDevice);
2019-07-08 09:38:39 +08:00
2019-07-18 18:25:57 +08:00
// 视图加载完成 回调
2019-07-25 18:25:04 +08:00
if (this.methods.viewLoaded instanceof Function) { this.methods.viewLoaded(this.mapDevice); }
2019-07-26 10:38:57 +08:00
}
2019-07-09 19:04:45 +08:00
setDefaultState() {
2019-07-11 17:58:58 +08:00
const list = [];
2019-07-09 19:04:45 +08:00
Object.values(this.mapDevice).forEach(elem => {
const code = elem.code;
2019-07-11 17:58:58 +08:00
const type = elem._type;
2019-07-26 17:13:03 +08:00
// 列车不需要设置默认状态
type != deviceType.Train && list.push(Object.assign({ code, _type: type }, this.defaultStateDict[type]));
2019-07-11 17:58:58 +08:00
});
2019-07-09 19:04:45 +08:00
this.update(list);
2019-07-10 16:04:17 +08:00
2019-07-25 18:25:04 +08:00
if (this.methods.stateLoaded instanceof Function) { this.methods.stateLoaded(list); }
2019-07-09 19:04:45 +08:00
}
2019-07-25 18:25:04 +08:00
setOptions(opts) {
2019-07-19 15:17:58 +08:00
const options = this.pullBack(opts);
this.$options.update(options);
2019-07-19 11:11:34 +08:00
this.$painter.updateTransform(this.$options);
2019-07-19 15:15:51 +08:00
2019-07-19 13:54:23 +08:00
if (this.$options.disabled == true) {
this.$mouseController.disable();
} else {
this.$mouseController.enable(opts);
}
2019-07-19 15:15:51 +08:00
2019-07-25 13:24:40 +08:00
if (this.methods.optionsUpdate instanceof Function) { this.methods.optionsUpdate(this.$options); }
2019-07-04 18:39:30 +08:00
}
2019-07-25 10:32:29 +08:00
setCenter(deviceCode) {
const device = this.mapDevice[deviceCode];
if (device && device.instance) {
var rect = createBoundingRect(device.instance);
2019-07-26 15:52:50 +08:00
var dcenter = calculateDCenter(rect, { width: this.$zr.getWidth(), height: this.$zr.getHeight() });
this.setOptions(dcenter);
2019-07-25 10:32:29 +08:00
}
}
2019-07-25 15:44:23 +08:00
setLayerVisible(layer) {
this.$painter.setLayerVisible(layer);
}
2019-08-15 16:19:03 +08:00
setLevelVisible(list) {
this.$painter.setLevelVisible(list);
2019-07-15 14:14:44 +08:00
}
2019-07-04 18:39:30 +08:00
render(list) {
(list || []).forEach(elem => {
2019-07-11 17:58:58 +08:00
const code = elem.code;
const type = elem._type;
const oDevice = this.mapDevice[code] || deviceFactory(type, elem);
2019-07-30 09:18:24 +08:00
const nDevice = Object.assign(oDevice || {}, elem);
2019-07-30 15:52:30 +08:00
this.dataSync(nDevice);
2019-07-18 17:21:18 +08:00
this.$painter.delete(oDevice);
2019-07-04 18:39:30 +08:00
if (!elem._dispose) {
2019-07-18 17:21:18 +08:00
this.mapDevice[code] = nDevice;
this.$painter.add(nDevice);
2019-07-04 18:39:30 +08:00
}
2019-07-11 17:58:58 +08:00
});
2019-07-10 16:04:17 +08:00
2019-07-25 18:25:04 +08:00
if (this.methods.viewUpdate instanceof Function) { this.methods.viewUpdate(list); }
2019-07-04 18:39:30 +08:00
}
2019-07-29 11:18:50 +08:00
// 中间处理
2019-08-07 11:22:33 +08:00
hookHandle(oDevice, elem) {
const code = elem.code;
const type = elem._type;
2019-07-29 11:18:50 +08:00
// 如果是延时计时,需要保存计数值到全局
if (type === deviceType.StationCounter) {
2019-07-29 11:18:50 +08:00
let val = '' + elem.val;
if (val === '0' || !elem.val) {
val = elem.val = localStore.get(code) || '0';
2019-07-29 11:18:50 +08:00
}
2019-07-26 18:54:42 +08:00
localStore(code, val);
2019-07-29 11:18:50 +08:00
}
2019-07-26 18:54:42 +08:00
2019-08-07 11:22:33 +08:00
for (var prop in elem) {
if (elem[prop] != oDevice[prop]) {
Object.assign(oDevice, elem);
return true;
}
}
return false;
2019-07-29 11:18:50 +08:00
}
2019-07-26 18:54:42 +08:00
2019-07-29 11:18:50 +08:00
// 后处理
postHandle(list) {
list.forEach(elem => {
const code = elem.code;
const type = elem._type;
if (type == deviceType.Switch) {
const item = this.mapDevice[code];
2019-07-26 18:54:42 +08:00
if (item) {
2019-07-30 09:18:24 +08:00
const sectionA = this.mapDevice[item.sectionACode];
const sectionB = this.mapDevice[item.sectionBCode];
const sectionC = this.mapDevice[item.sectionCCode];
2019-07-26 18:54:42 +08:00
if (sectionA && sectionB && sectionC) {
2019-07-30 09:18:24 +08:00
item['cutOff'] = sectionA.cutOff;
item['sectionAstatus'] = sectionA.status;
item['sectionBstatus'] = sectionB.status;
item['sectionCstatus'] = sectionC.status;
2019-07-26 18:54:42 +08:00
}
}
2019-07-29 11:18:50 +08:00
this.$painter.update(item);
2019-07-26 18:54:42 +08:00
}
if (type == deviceType.Section) {
const item = this.mapDevice[code];
2019-07-26 18:54:42 +08:00
if (item) {
2019-07-30 09:18:24 +08:00
const swch = this.mapDevice[item.relSwitchCode];
2019-07-26 18:54:42 +08:00
if (swch) {
2019-07-30 09:18:24 +08:00
const sectionA = this.mapDevice[swch.sectionACode];
const sectionB = this.mapDevice[swch.sectionBCode];
const sectionC = this.mapDevice[swch.sectionCCode];
2019-07-26 18:54:42 +08:00
if (sectionA && sectionB && sectionC) {
2019-08-06 18:42:18 +08:00
swch['cutOff'] = sectionA.cutOff;
2019-07-30 09:18:24 +08:00
swch['sectionAstatus'] = sectionA.status;
swch['sectionBstatus'] = sectionB.status;
swch['sectionCstatus'] = sectionC.status;
2019-07-26 18:54:42 +08:00
}
2019-07-29 11:18:50 +08:00
this.$painter.update(swch);
2019-07-26 18:54:42 +08:00
}
}
}
});
}
2019-07-04 18:39:30 +08:00
update(list) {
2019-07-29 11:18:50 +08:00
(list || []).forEach(elem => {
2019-07-11 17:58:58 +08:00
const code = elem.code;
const type = elem._type;
const oDevice = this.mapDevice[code] || deviceFactory(type, elem);
2019-07-30 17:27:29 +08:00
if (elem.dispose) {
2019-07-18 18:25:57 +08:00
this.$painter.delete(oDevice);
2019-07-04 18:39:30 +08:00
} else {
2019-08-07 11:22:33 +08:00
if (this.hookHandle(oDevice, elem)) {
this.$painter.update(oDevice);
}
2019-07-04 18:39:30 +08:00
}
2019-07-11 17:58:58 +08:00
});
2019-07-10 16:04:17 +08:00
2019-07-29 11:18:50 +08:00
// 状态后处理
this.postHandle(list || []);
2019-07-29 11:18:50 +08:00
2019-07-25 18:25:04 +08:00
if (this.methods.stateUpdate instanceof Function) { this.methods.stateUpdate(list); }
2019-07-10 16:04:17 +08:00
}
2019-07-25 15:44:23 +08:00
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 || {};
}
2019-07-30 15:52:30 +08:00
dataSync(model) {
var prop = null;
var type = model._type;
var code = model.code;
switch (type) {
2019-07-11 17:58:58 +08:00
case deviceType.Link: prop = 'linkList'; break;
2019-07-30 15:52:30 +08:00
case deviceType.Section: prop = 'sectionList'; break;
2019-07-16 09:44:31 +08:00
case deviceType.Switch: prop = 'switchList'; break;
case deviceType.Signal: prop = 'signalList'; break;
2019-07-15 15:25:49 +08:00
case deviceType.Station: prop = 'stationList'; break;
2019-07-16 09:44:31 +08:00
case deviceType.StationStand: prop = 'stationStandList'; break;
2019-07-15 15:25:49 +08:00
case deviceType.StationControl: prop = 'stationControlList'; break;
2019-07-16 09:44:31 +08:00
case deviceType.StationCounter: prop = 'stationCounterList'; break;
case deviceType.ZcControl: prop = 'zcControlList'; break;
case deviceType.StationDelayUnlock: prop = 'stationDelayUnlockList'; break;
case deviceType.LcControl: prop = 'lcControlList'; break;
2019-07-15 15:25:49 +08:00
case deviceType.LimitControl: prop = 'tempSpeedLimitList'; break;
2019-07-16 09:44:31 +08:00
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;
2019-07-10 16:04:17 +08:00
}
2019-07-30 15:52:30 +08:00
const list = this.data[prop] || [];
const idex = list.findIndex(elem => { return elem.code == code; });
2019-07-10 16:04:17 +08:00
if (list) {
2019-07-30 15:52:30 +08:00
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));
2019-07-18 18:24:40 +08:00
}
}
2019-07-10 16:04:17 +08:00
}
2019-07-04 18:39:30 +08:00
}
2019-07-09 19:04:45 +08:00
getZr() {
2019-07-10 13:17:12 +08:00
return this.$zr;
2019-07-09 19:04:45 +08:00
}
getEvents() {
2019-07-15 09:38:35 +08:00
return this.events;
2019-07-04 10:59:40 +08:00
}
2019-07-15 14:01:57 +08:00
getDeviceByCode(code) {
return this.mapDevice[code];
}
2019-07-30 18:02:58 +08:00
getShapeTipPoint(opts) {
const device = this.mapDevice[opts.code];
if (device) {
return this.$painter.getShapeTipPoint(device.instance, opts);
}
}
2019-07-19 11:11:34 +08:00
resize(opt) {
this.$zr.resize(opt);
2019-07-25 10:30:30 +08:00
this.$painter.updateZrSize(opt);
2019-07-19 11:11:34 +08:00
}
2019-07-10 16:04:17 +08:00
refresh() {
this.$painter.refresh();
}
2019-07-26 17:13:03 +08:00
clearTrainView() {
this.$painter.clearLevel(deviceType.Train);
2019-07-30 16:47:11 +08:00
zrUtil.each(Object.values(this.mapDevice), device => {
if (device._type == deviceType.Train) {
device.instance = null;
}
});
2019-07-26 17:13:03 +08:00
}
2019-07-10 16:04:17 +08:00
clear() {
2019-08-14 09:35:38 +08:00
this.skinCode = '';
2019-07-30 16:47:11 +08:00
this.style = {};
this.mapDevice = {};
2019-07-10 16:04:17 +08:00
this.$painter.clear();
}
dispose() {
2019-07-15 09:38:35 +08:00
this.off(this.events.Pan, this.optionsHandler);
this.off(this.events.Zoom, this.optionsHandler);
2019-07-10 16:04:17 +08:00
this.clear();
2019-07-10 16:04:17 +08:00
2019-07-15 09:38:35 +08:00
this.$mouseController.dispose();
2019-07-10 16:04:17 +08:00
this.$zr && zrender.dispose(this.$zr);
this.$painter.dispose();
}
2019-07-10 12:02:02 +08:00
on(eventname, cb, context) {
2019-07-15 09:38:35 +08:00
const idx = Object.values(this.events).indexOf(eventname);
2019-07-10 12:02:02 +08:00
if (idx >= 0) {
switch (eventname) {
2019-07-25 10:32:29 +08:00
case this.events.Selected:
this.$mouseController.on(this.events.Selected, cb, context);
2019-07-11 17:58:58 +08:00
break;
2019-07-25 10:32:29 +08:00
case this.events.Contextmenu:
this.$mouseController.on(this.events.Contextmenu, cb, context);
2019-07-11 17:58:58 +08:00
break;
2019-07-25 18:25:04 +08:00
case this.events.DataZoom:
this.$mouseController.on(this.events.DataZoom, cb, context);
break;
2019-07-10 12:02:02 +08:00
}
}
}
off(eventname, cb) {
2019-07-15 09:38:35 +08:00
const idx = Object.values(this.events).indexOf(eventname);
2019-07-10 12:02:02 +08:00
if (idx >= 0) {
switch (eventname) {
2019-07-25 10:32:29 +08:00
case this.events.Selected:
this.$mouseController.off(this.events.Selected, cb);
2019-07-11 17:58:58 +08:00
break;
2019-07-25 10:32:29 +08:00
case this.events.Contextmenu:
this.$mouseController.off(this.events.Contextmenu, cb);
2019-07-11 17:58:58 +08:00
break;
2019-07-25 18:25:04 +08:00
case this.events.DataZoom:
this.$mouseController.off(this.events.DataZoom, cb);
break;
2019-07-10 12:02:02 +08:00
}
}
}
2019-07-03 14:29:09 +08:00
}
2019-07-25 10:32:29 +08:00
export default Jlmap;