light-chart
Version:
Charts for mobile visualization.
156 lines (134 loc) • 5.42 kB
JavaScript
const Util = require('../../util/common');
const Helper = require('../helper');
const TOUCH_EVENTS = [
'touchstart',
'touchmove',
'touchend',
'touchStart',
'touchMove',
'touchEnd'
];
const DAY_TIMESTAMPS = 86400000;
module.exports = {
_handleMove(e) {
if (e.type === 'swipe' && e.deltaTime > 350) { // 区分 pan 操作和 swipe 操作
return null;
}
const { currentDeltaX, currentDeltaY, lastPoint } = this;
let deltaX;
let deltaY;
if (TOUCH_EVENTS.indexOf(e.type) !== -1) { // support touch and miniprogram
const currentPoint = e.touches[0];
deltaX = currentPoint.x - lastPoint.x;
deltaY = currentPoint.y - lastPoint.y;
this.lastPoint = currentPoint;
} else if (currentDeltaX !== null && currentDeltaY !== null) {
deltaX = e.deltaX - currentDeltaX;
deltaY = e.deltaY - currentDeltaY;
this.currentDeltaX = e.deltaX;
this.currentDeltaY = e.deltaY;
}
if (Math.abs(deltaX) > 0 || Math.abs(deltaY) > 0) {
const lastTimestamp = this._timestamp;
const now = +new Date();
if ((now - lastTimestamp) > 16) {
this._doMove(deltaX, deltaY);
this._timestamp = now;
}
}
},
_doMove(deltaX, deltaY) {
const self = this;
const { mode, chart, limitRange } = self;
const coord = chart.get('coord');
const { start, end } = coord;
const data = chart.get('data');
if (Util.directionEnabled(mode, 'x') && deltaX !== 0) {
const xScale = chart.getXScale();
const xField = xScale.field;
if (!limitRange[xField]) {
limitRange[xField] = Helper.getLimitRange(data, xScale);
}
const coordWidth = end.x - start.x;
if (xScale.isCategory) {
self._handleCatScale(xScale, deltaX, coordWidth);
} else if (xScale.isLinear) {
self._handleLinearScale(xScale, deltaX, coordWidth, 'x');
}
const xDef = Helper.getColDef(chart, xField);
self.xRange = Helper.getFieldRange(xDef, limitRange[xField], xScale.type);
}
if (Util.directionEnabled(mode, 'y') && deltaY !== 0) {
const coordHeight = start.y - end.y;
const yScales = chart.getYScales();
Util.each(yScales, yScale => {
const yField = yScale.field;
if (!limitRange[yField]) {
limitRange[yField] = Helper.getLimitRange(data, yScale);
}
yScale.isLinear && self._handleLinearScale(yScale, deltaY, coordHeight, 'y');
});
const yDef = Helper.getColDef(chart, yScales[0].field);
self.yRange = Helper.getFieldRange(yDef, limitRange[yScales[0].field], yScales[0].type);
}
chart.repaint();
},
_handleLinearScale(scale, delta, range, flag) {
const { field, min, max } = scale;
const limitRange = this.limitRange;
if (min === limitRange[field].min && max === limitRange[field].max) return;
const ratio = delta / range;
const panValue = ratio * (max - min);
let newMax = flag === 'x' ? max - panValue : max + panValue;
let newMin = flag === 'x' ? min - panValue : min + panValue;
if (limitRange[field] && !Util.isNil(limitRange[field].min) && newMin <= limitRange[field].min) {
newMin = limitRange[field].min;
newMax = (max - min) + newMin;
}
if (limitRange[field] && !Util.isNil(limitRange[field].max) && newMax >= limitRange[field].max) {
newMax = limitRange[field].max;
newMin = newMax - (max - min);
}
this.updateLinearScale(field, newMin, newMax);
},
_handleCatScale(scale, delta, range) {
const { type, field, values, ticks } = scale;
const duplicateRemovalValues = Util.uniq(values);
const originValues = this.limitRange[field];
const lastValueIndex = originValues.length - 1;
const currentLength = duplicateRemovalValues.length;
const speed = this.speed || 1;
const step = range / (currentLength * speed);
const firstIndex = originValues.indexOf(duplicateRemovalValues[0]);
const lastIndex = originValues.indexOf(duplicateRemovalValues[currentLength - 1]);
let minIndex = firstIndex;
let maxIndex = lastIndex;
const ratio = Math.abs(delta / range);
const panStep = this.step || Math.max(1, parseInt(ratio * currentLength));
this._panCumulativeDelta += delta;
minIndex = this._panCumulativeDelta > step ?
Math.max(0, minIndex - panStep) :
(this._panCumulativeDelta < -step ? Math.min(lastValueIndex - currentLength + 1, minIndex + panStep) : minIndex);
maxIndex = Math.min(lastValueIndex, minIndex + currentLength - 1);
if (minIndex === firstIndex && maxIndex === lastIndex) {
return null;
}
const newValues = originValues.slice(minIndex, maxIndex + 1);
let newTicks = null;
if (type === 'timeCat') {
const tickGap = ticks.length > 2 ? ticks[1] - ticks[0] : DAY_TIMESTAMPS;
if (this._panCumulativeDelta > step) {
for (let i = ticks[0] - tickGap; i >= newValues[0]; i -= tickGap) {
ticks.unshift(i);
}
} else if (this._panCumulativeDelta < -step) {
for (let i = ticks[ticks.length - 1] + tickGap; i <= newValues[newValues.length - 1]; i += tickGap) {
ticks.push(i);
}
}
newTicks = ticks;
}
this.updateCatScale(field, newValues, newTicks, originValues, minIndex, maxIndex);
this._panCumulativeDelta = minIndex !== firstIndex ? 0 : this._panCumulativeDelta;
}
};