blob: df98b4533c9b2fa5ee2ec2061a9ccef65dab3e1e [file] [log] [blame]
// Only create one roam controller for each coordinate system.
// one roam controller might be refered by two inside data zoom
// components (for example, one for x and one for y). When user
// pan or zoom, only dispatch one action for those data zoom
// components.
import * as zrUtil from 'zrender/src/core/util';
import RoamController from '../../component/helper/RoamController';
import * as throttleUtil from '../../util/throttle';
var curry = zrUtil.curry;
var ATTR = '\0_ec_dataZoom_roams';
/**
* @public
* @param {module:echarts/ExtensionAPI} api
* @param {Object} dataZoomInfo
* @param {string} dataZoomInfo.coordId
* @param {Function} dataZoomInfo.containsPoint
* @param {Array.<string>} dataZoomInfo.allCoordIds
* @param {string} dataZoomInfo.dataZoomId
* @param {number} dataZoomInfo.throttleRate
* @param {Function} dataZoomInfo.panGetRange
* @param {Function} dataZoomInfo.zoomGetRange
* @param {boolean} [dataZoomInfo.zoomLock]
* @param {boolean} [dataZoomInfo.disabled]
*/
export function register(api, dataZoomInfo) {
var store = giveStore(api);
var theDataZoomId = dataZoomInfo.dataZoomId;
var theCoordId = dataZoomInfo.coordId; // Do clean when a dataZoom changes its target coordnate system.
// Avoid memory leak, dispose all not-used-registered.
zrUtil.each(store, function (record, coordId) {
var dataZoomInfos = record.dataZoomInfos;
if (dataZoomInfos[theDataZoomId] && zrUtil.indexOf(dataZoomInfo.allCoordIds, theCoordId) < 0) {
delete dataZoomInfos[theDataZoomId];
record.count--;
}
});
cleanStore(store);
var record = store[theCoordId]; // Create if needed.
if (!record) {
record = store[theCoordId] = {
coordId: theCoordId,
dataZoomInfos: {},
count: 0
};
record.controller = createController(api, record);
record.dispatchAction = zrUtil.curry(dispatchAction, api);
} // Update reference of dataZoom.
!record.dataZoomInfos[theDataZoomId] && record.count++;
record.dataZoomInfos[theDataZoomId] = dataZoomInfo;
var controllerParams = mergeControllerParams(record.dataZoomInfos);
record.controller.enable(controllerParams.controlType, controllerParams.opt); // Consider resize, area should be always updated.
record.controller.setPointerChecker(dataZoomInfo.containsPoint); // Update throttle.
throttleUtil.createOrUpdate(record, 'dispatchAction', dataZoomInfo.throttleRate, 'fixRate');
}
/**
* @public
* @param {module:echarts/ExtensionAPI} api
* @param {string} dataZoomId
*/
export function unregister(api, dataZoomId) {
var store = giveStore(api);
zrUtil.each(store, function (record) {
record.controller.dispose();
var dataZoomInfos = record.dataZoomInfos;
if (dataZoomInfos[dataZoomId]) {
delete dataZoomInfos[dataZoomId];
record.count--;
}
});
cleanStore(store);
}
/**
* @public
*/
export function shouldRecordRange(payload, dataZoomId) {
if (payload && payload.type === 'dataZoom' && payload.batch) {
for (var i = 0, len = payload.batch.length; i < len; i++) {
if (payload.batch[i].dataZoomId === dataZoomId) {
return false;
}
}
}
return true;
}
/**
* @public
*/
export function generateCoordId(coordModel) {
return coordModel.type + '\0_' + coordModel.id;
}
/**
* Key: coordId, value: {dataZoomInfos: [], count, controller}
* @type {Array.<Object>}
*/
function giveStore(api) {
// Mount store on zrender instance, so that we do not
// need to worry about dispose.
var zr = api.getZr();
return zr[ATTR] || (zr[ATTR] = {});
}
function createController(api, newRecord) {
var controller = new RoamController(api.getZr());
controller.on('pan', curry(onPan, newRecord));
controller.on('zoom', curry(onZoom, newRecord));
return controller;
}
function cleanStore(store) {
zrUtil.each(store, function (record, coordId) {
if (!record.count) {
record.controller.dispose();
delete store[coordId];
}
});
}
function onPan(record, dx, dy, oldX, oldY, newX, newY) {
wrapAndDispatch(record, function (info) {
return info.panGetRange(record.controller, dx, dy, oldX, oldY, newX, newY);
});
}
function onZoom(record, scale, mouseX, mouseY) {
wrapAndDispatch(record, function (info) {
return info.zoomGetRange(record.controller, scale, mouseX, mouseY);
});
}
function wrapAndDispatch(record, getRange) {
var batch = [];
zrUtil.each(record.dataZoomInfos, function (info) {
var range = getRange(info);
!info.disabled && range && batch.push({
dataZoomId: info.dataZoomId,
start: range[0],
end: range[1]
});
});
record.dispatchAction(batch);
}
/**
* This action will be throttled.
*/
function dispatchAction(api, batch) {
api.dispatchAction({
type: 'dataZoom',
batch: batch
});
}
/**
* Merge roamController settings when multiple dataZooms share one roamController.
*/
function mergeControllerParams(dataZoomInfos) {
var controlType;
var opt = {};
var typePriority = {
'true': 2,
'move': 1,
'false': 0,
'undefined': -1
};
zrUtil.each(dataZoomInfos, function (dataZoomInfo) {
var oneType = dataZoomInfo.disabled ? false : dataZoomInfo.zoomLock ? 'move' : true;
typePriority[oneType] > typePriority[controlType] && (controlType = oneType); // Do not support that different 'shift'/'ctrl'/'alt' setting used in one coord sys.
zrUtil.extend(opt, dataZoomInfo.roamControllerOpt);
});
return {
controlType: controlType,
opt: opt
};
}