修改代码

This commit is contained in:
ival 2019-07-10 16:04:17 +08:00
parent d13bf6876b
commit 76fef48d87
4 changed files with 297 additions and 99 deletions

View File

@ -55,9 +55,11 @@ class Jmap {
this.$mouseController = new MouseController(this); this.$mouseController = new MouseController(this);
this.$mouseController.enable(); this.$mouseController.enable();
this.$optionsHandler = this.setOptions.bind(this); this.optionsHandler = this.setOptions.bind(this);
this.$mouseController.on(this.Events.Pan, this.$optionsHandler);
this.$mouseController.on(this.Events.Zoom, this.$optionsHandler); this.$mouseController.on(this.Events.Pan, this.optionsHandler);
this.$mouseController.on(this.Events.Zoom, this.optionsHandler);
} }
loadData(data) { loadData(data) {
@ -76,14 +78,14 @@ class Jmap {
// 生成代理对象 // 生成代理对象
this.proxyData = new Proxy(this.mapDevice, new ProxyHandle(this.$painter)); this.proxyData = new Proxy(this.mapDevice, new ProxyHandle(this.$painter));
// 数据加载完成回调 // 数据加载完成
(this.methods.dataLoaded instanceof Function) && this.methods.dataLoaded(); if (this.methods.dataLoaded instanceof Function) { this.methods.dataLoaded(); }
// 初次渲染视图 // 初次渲染视图
this.$painter.repaint(this.mapDevice, this.styleDict); this.$painter.repaint(this.mapDevice, this.styleDict);
// 视图渲染完成回调 // 视图加载完成
(this.methods.viewLoaded instanceof Function) && this.methods.viewLoaded(); if (this.methods.viewLoaded instanceof Function) { this.methods.viewLoaded(); }
} }
loadStyle(skinStyle) { loadStyle(skinStyle) {
@ -113,14 +115,49 @@ class Jmap {
}) })
this.update(list); this.update(list);
if (this.methods.stateLoaded instanceof Function) { this.methods.stateLoaded(); }
} }
setOptions(zoom) { setOptions(zoom) {
this.$options.update(zoom); this.$options.update(zoom);
this.$painter.updateZoomTransform(this.$options); this.$painter.updateZoomTransform(this.$options);
if (this.methods.optionsUpdate instanceof Function) { this.methods.optionsUpdate(); }
} }
syncData(model) { render(list) {
(list || []).forEach(elem => {
let type = elem.type;
let code = elem.code;
let device = this.proxyData[code] || deviceFactory(type, this.styleDict[type], elem);
let model = Object.assign(device.model || {}, elem);
delete this.proxyData[code];
if (!elem._dispose) {
this.proxyData[code] = Object.assign(device, { model });
}
this.dataSync(model);
})
if (this.methods.viewUpdate instanceof Function) { this.methods.viewUpdate(); }
}
update(list) {
(list || []).forEach(elem => {
let code = elem.code;
if (elem._dispose) {
delete this.proxyData[code];
} else {
let device = this.proxyData[code] || {};
let state = Object.assign(device.state || {}, elem);
this.proxyData[code] = Object.assign(device, { state });
}
})
if (this.methods.stateUpdate instanceof Function) { this.methods.stateUpdate(); }
}
dataSync(model) {
let code = model.code; let code = model.code;
let type = model.type; let type = model.type;
let dispose = model._dispose; let dispose = model._dispose;
@ -141,34 +178,6 @@ class Jmap {
} }
} }
render(list) {
(list || []).forEach(elem => {
let type = elem.type;
let code = elem.code;
let device = this.proxyData[code] || deviceFactory(type, this.styleDict[type], elem);
let model = Object.assign(device.model || {}, elem);
delete this.proxyData[code];
if (!elem._dispose) {
device = this.proxyData[code] = Object.assign(device, { model });
}
this.syncData(model);
})
}
update(list) {
(list || []).forEach(elem => {
let code = elem.code;
if (elem._dispose) {
delete this.proxyData[code];
} else {
let device = this.proxyData[code] || {};
let state = Object.assign(device.state || {}, elem);
this.proxyData[code] = Object.assign(device, { state });
}
})
}
getZr() { getZr() {
return this.$zr; return this.$zr;
} }
@ -197,6 +206,28 @@ class Jmap {
return this.mapDevice; return this.mapDevice;
} }
refresh() {
this.$painter.refresh();
}
clear() {
this.$painter.clear();
}
dispose() {
this.off(this.Events.Pan, this.optionsHandler);
this.off(this.Events.Zoom, this.optionsHandler);
this.skinStyle = '';
this.styleDict = {};
this.mapDevice = {};
this.proxyData = {};
this.$mouseController.dispose && this.$mouseController.dispose();
this.$zr && zrender.dispose(this.$zr);
this.$painter.dispose();
}
on(eventname, cb, context) { on(eventname, cb, context) {
let idx = Object.values(this.Events).indexOf(eventname); let idx = Object.values(this.Events).indexOf(eventname);
if (idx >= 0) { if (idx >= 0) {
@ -229,24 +260,6 @@ class Jmap {
} }
} }
refresh() {
this.$painter.refresh();
}
clear() {
this.$painter.clear();
}
dispose() {
this.off(this.Events.Pan, this.$optionsHandler);
this.off(this.Events.Zoom, this.$optionsHandler);
this.skinStyle = '';
this.styleDict = {};
this.mapDevice = {};
this.proxyData = {};
this.$zr && zrender.dispose(this.$zr);
this.$painter.dispose();
}
} }
export default Jmap; export default Jmap;

View File

@ -31,43 +31,54 @@ class MouseController extends Eventful {
constructor(jmap) { constructor(jmap) {
super(); super();
this.Events = jmap.getEvents(); this.Events = jmap.getEvents();
this.initController(jmap.getZr());
}
let clickHandler = this.click.bind(this); initController(zr) {
let contextmenuHandler = this.contextmenu.bind(this); if (zr) {
let moveEventHandler = this.moveEvent.bind(this); let clickHandler = this.click.bind(this);
let contextmenuHandler = this.contextmenu.bind(this);
let moveEventHandler = this.moveEvent.bind(this);
let mousedownHandler = this.mousedown.bind(this); let mousedownHandler = this.mousedown.bind(this);
let mousemoveHandler = this.mousemove.bind(this); let mousemoveHandler = this.mousemove.bind(this);
let mouseupHandler = this.mouseup.bind(this); let mouseupHandler = this.mouseup.bind(this);
let mousewheelHandler = this.mousewheel.bind(this); let mousewheelHandler = this.mousewheel.bind(this);
this.$zr = jmap.getZr(); zr.on('click', clickHandler);
this.$zr.on('click', clickHandler); zr.on('contextmenu', contextmenuHandler);
this.$zr.on('contextmenu', contextmenuHandler); zr.on('mousemove', moveEventHandler);
this.$zr.on('mousemove', moveEventHandler);
this.enable = function (opts) { this.enable = function (opts) {
opts = opts || {}; opts = opts || {};
this._moveOnMouseMove = opts.moveOnMouseMove || true; this._moveOnMouseMove = opts.moveOnMouseMove || true;
this._zoomOnMouseWheel = opts.zoomOnMouseWheel || true; this._zoomOnMouseWheel = opts.zoomOnMouseWheel || true;
this._preventDefaultMouseMove = opts.preventDefaultMouseMove || true; this._preventDefaultMouseMove = opts.preventDefaultMouseMove || true;
this.disable(); this.disable();
this.$zr.on('mousedown', mousedownHandler); zr.on('mousedown', mousedownHandler);
this.$zr.on('mousemove', mousemoveHandler); zr.on('mousemove', mousemoveHandler);
this.$zr.on('mouseup', mouseupHandler); zr.on('mouseup', mouseupHandler);
this.$zr.on('mousewheel', mousewheelHandler); zr.on('mousewheel', mousewheelHandler);
}
this.disable = function () {
zr.off('mousedown', mousedownHandler);
zr.off('mousemove', mouseupHandler);
zr.off('mouseup', mousemoveHandler);
zr.off('mousewheel', mousewheelHandler);
}
this.dispose = function () {
zr.off('click', clickHandler);
zr.off('contextmenu', contextmenuHandler);
zr.off('mousemove', moveEventHandler);
this.disable();
}
this.isDragging = function () { return this._dragging; }
} }
this.disable = function () {
this.$zr.off('mousedown', mousedownHandler);
this.$zr.off('mousemove', mouseupHandler);
this.$zr.off('mouseup', mousemoveHandler);
this.$zr.off('mousewheel', mousewheelHandler);
}
this.isDragging = function () { return this._dragging; }
} }
mousedown(e) { mousedown(e) {

174
src/jmap/utils/throttle.js Normal file
View File

@ -0,0 +1,174 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
var ORIGIN_METHOD = '\0__throttleOriginMethod';
var RATE = '\0__throttleRate';
var THROTTLE_TYPE = '\0__throttleType';
/**
* @public
* @param {(Function)} fn
* @param {number} [delay=0] Unit: ms.
* @param {boolean} [debounce=false]
* true: If call interval less than `delay`, only the last call works.
* false: If call interval less than `delay, call works on fixed rate.
* @return {(Function)} throttled fn.
*/
export function throttle(fn, delay, debounce) {
var currCall;
var lastCall = 0;
var lastExec = 0;
var timer = null;
var diff;
var scope;
var args;
var debounceNextCall;
delay = delay || 0;
function exec() {
lastExec = (new Date()).getTime();
timer = null;
fn.apply(scope, args || []);
}
var cb = function () {
currCall = (new Date()).getTime();
scope = this;
args = arguments;
var thisDelay = debounceNextCall || delay;
var thisDebounce = debounceNextCall || debounce;
debounceNextCall = null;
diff = currCall - (thisDebounce ? lastCall : lastExec) - thisDelay;
clearTimeout(timer);
// Here we should make sure that: the `exec` SHOULD NOT be called later
// than a new call of `cb`, that is, preserving the command order. Consider
// calculating "scale rate" when roaming as an example. When a call of `cb`
// happens, either the `exec` is called dierectly, or the call is delayed.
// But the delayed call should never be later than next call of `cb`. Under
// this assurance, we can simply update view state each time `dispatchAction`
// triggered by user roaming, but not need to add extra code to avoid the
// state being "rolled-back".
if (thisDebounce) {
timer = setTimeout(exec, thisDelay);
}
else {
if (diff >= 0) {
exec();
}
else {
timer = setTimeout(exec, -diff);
}
}
lastCall = currCall;
};
/**
* Clear throttle.
* @public
*/
cb.clear = function () {
if (timer) {
clearTimeout(timer);
timer = null;
}
};
/**
* Enable debounce once.
*/
cb.debounceNextCall = function (debounceDelay) {
debounceNextCall = debounceDelay;
};
return cb;
}
/**
* Create throttle method or update throttle rate.
*
* @example
* ComponentView.prototype.render = function () {
* ...
* throttle.createOrUpdate(
* this,
* '_dispatchAction',
* this.model.get('throttle'),
* 'fixRate'
* );
* };
* ComponentView.prototype.remove = function () {
* throttle.clear(this, '_dispatchAction');
* };
* ComponentView.prototype.dispose = function () {
* throttle.clear(this, '_dispatchAction');
* };
*
* @public
* @param {Object} obj
* @param {string} fnAttr
* @param {number} [rate]
* @param {string} [throttleType='fixRate'] 'fixRate' or 'debounce'
* @return {Function} throttled function.
*/
export function createOrUpdate(obj, fnAttr, rate, throttleType) {
var fn = obj[fnAttr];
if (!fn) {
return;
}
var originFn = fn[ORIGIN_METHOD] || fn;
var lastThrottleType = fn[THROTTLE_TYPE];
var lastRate = fn[RATE];
if (lastRate !== rate || lastThrottleType !== throttleType) {
if (rate == null || !throttleType) {
return (obj[fnAttr] = originFn);
}
fn = obj[fnAttr] = throttle(
originFn, rate, throttleType === 'debounce'
);
fn[ORIGIN_METHOD] = originFn;
fn[THROTTLE_TYPE] = throttleType;
fn[RATE] = rate;
}
return fn;
}
/**
* Clear throttle. Example see throttle.createOrUpdate.
*
* @public
* @param {Object} obj
* @param {string} fnAttr
*/
export function clear(obj, fnAttr) {
var fn = obj[fnAttr];
if (fn && fn[ORIGIN_METHOD]) {
obj[fnAttr] = fn[ORIGIN_METHOD];
}
}

View File

@ -32,34 +32,34 @@
dataLoaded() { console.log('dataLoaded'); }, dataLoaded() { console.log('dataLoaded'); },
viewLoaded() { console.log('viewLoaded'); }, viewLoaded() { console.log('viewLoaded'); },
stateLoaded() { console.log('stateLoaded'); }, stateLoaded() { console.log('stateLoaded'); },
stateUpdated() { console.log('stateUpdated'); } viewUpdate() { console.log('viewUpdate'); },
stateUpdate() { console.log('stateUpdate'); },
optionsUpdate() { console.log('optionsUpdate'); },
} }
}); });
let list = [ let list = [];
{ code: '1', beg: { x: 20, y: 50 }, end: { x: 120, y: 50 } }
];
for (var i = 1; i < 10; i++) { for (var i = 1; i < 50; i++) {
for (var j = 1; j < 1000; j++) { for (var j = 1; j < 100; j++) {
list.push({ code: `${i}${j}`, beg: { x: i * 120 + 50, y: j * 20 + 50 }, end: { x: i * 120 + 150, y: j * 20 + 50 } }); list.push({ code: `${i}${j}`, beg: { x: i * 120 + 50, y: j * 20 + 50 }, end: { x: i * 120 + 150, y: j * 20 + 50 } });
} }
} }
this.jmap.loadData({ skinStyle: '01', linkList: list }); this.jmap.loadData({ skinStyle: '01', linkList: list });
this.jmap.setDefaultState(); // this.jmap.setDefaultState();
// this.jmap.render([ // this.jmap.render([
// {code: '11', type: 'Link', beg: { x: 20 , y: 100}, end: { x: 120, y: 100 }} // {code: '11', type: 'Link', beg: { x: 20 , y: 100}, end: { x: 120, y: 100 }}
// ]); // ]);
this.jmap.update([ // this.jmap.update([
{ code: '11', type: 'Link', status: '02' } // { code: '11', type: 'Link', status: '02' }
]); // ]);
// this.jmap.render([ // this.jmap.render([
// {code: '11', type: 'Link', beg: { x: 0 , y: 0}, end: { x: 200, y: 200 }} // { code: '11', type: 'Link', beg: { x: 0, y: 0 }, end: { x: 200, y: 200 } }
// ]); // ]);
// this.jmap.update([]); // this.jmap.update([]);
@ -74,11 +74,11 @@
this.jmap = null; this.jmap = null;
}, },
methods: { methods: {
selected() { selected(e) {
console.log(this, 'selected'); console.log('selected', e);
}, },
contextmenu() { contextmenu(e) {
console.log(this, 'contextmenu'); console.log('contextmenu', e);
} }
} }
}; };