570 lines
13 KiB
Java
570 lines
13 KiB
Java
/**
|
||
* @fileOverview The controller of axis
|
||
* @author sima.zhang
|
||
*/
|
||
var Util = require('../../util');
|
||
|
||
var _require = require('@antv/component/lib'),
|
||
Axis = _require.Axis;
|
||
|
||
var vec2 = Util.MatrixUtil.vec2;
|
||
|
||
function formatTicks(ticks) {
|
||
var tmp = [];
|
||
|
||
if (ticks.length > 0) {
|
||
tmp = ticks.slice(0);
|
||
var first = tmp[0];
|
||
var last = tmp[tmp.length - 1];
|
||
|
||
if (first.value !== 0) {
|
||
tmp.unshift({
|
||
value: 0
|
||
});
|
||
}
|
||
|
||
if (last.value !== 1) {
|
||
tmp.push({
|
||
value: 1
|
||
});
|
||
}
|
||
}
|
||
|
||
return tmp;
|
||
}
|
||
|
||
function fillAxisTicks(ticks, isLinear, gridCentering) {
|
||
var result = [];
|
||
if (ticks.length < 1) return result;
|
||
|
||
if (ticks.length >= 2 && isLinear && gridCentering) {
|
||
result.push({
|
||
text: '',
|
||
tickValue: '',
|
||
value: 0
|
||
});
|
||
}
|
||
|
||
if (ticks[0].value !== 0) {
|
||
result.push({
|
||
text: '',
|
||
tickValue: '',
|
||
value: 0
|
||
});
|
||
}
|
||
|
||
result = result.concat(ticks);
|
||
|
||
if (result[result.length - 1].value !== 1) {
|
||
result.push({
|
||
text: '',
|
||
tickValue: '',
|
||
value: 1
|
||
});
|
||
}
|
||
|
||
return result;
|
||
}
|
||
|
||
function getDefaultValueFromPosition(position, val) {
|
||
if (val === void 0) {
|
||
val = 0;
|
||
}
|
||
|
||
if (position === 'middle') {
|
||
val = 0.5;
|
||
}
|
||
|
||
if (position.includes('%')) {
|
||
val = parseInt(position, 10) / 100;
|
||
}
|
||
|
||
return val;
|
||
}
|
||
|
||
var AxisController = /*#__PURE__*/function () {
|
||
function AxisController(cfg) {
|
||
this.visible = true;
|
||
this.canvas = null;
|
||
this.container = null;
|
||
this.coord = null;
|
||
this.options = null;
|
||
this.axes = [];
|
||
Util.mix(this, cfg);
|
||
}
|
||
|
||
var _proto = AxisController.prototype;
|
||
|
||
_proto._isHide = function _isHide(field) {
|
||
// 对应的坐标轴是否隐藏
|
||
var options = this.options;
|
||
|
||
if (options && options[field] === false) {
|
||
return true;
|
||
}
|
||
|
||
return false;
|
||
};
|
||
|
||
_proto._getMiddleValue = function _getMiddleValue(curValue, ticks, index, isLinear) {
|
||
if (curValue === 0 && !isLinear) {
|
||
return 0;
|
||
}
|
||
|
||
if (curValue === 1) {
|
||
return 1;
|
||
}
|
||
|
||
var nextValue = ticks[index + 1].value;
|
||
|
||
if (!isLinear && nextValue === 1) {
|
||
return 1;
|
||
}
|
||
|
||
return (curValue + nextValue) / 2;
|
||
};
|
||
|
||
_proto._getLineRange = function _getLineRange(coord, scale, dimType, index) {
|
||
var start;
|
||
var end;
|
||
var isVertical;
|
||
var field = scale.field;
|
||
var options = this.options;
|
||
var position = '';
|
||
|
||
if (options[field] && options[field].position) {
|
||
position = options[field].position;
|
||
} // TODO middle & percentage for position
|
||
|
||
|
||
if (dimType === 'x') {
|
||
// x轴的坐标轴,底部的横坐标
|
||
var y = position === 'top' ? 1 : 0;
|
||
y = getDefaultValueFromPosition(position, y);
|
||
start = {
|
||
x: 0,
|
||
y: y
|
||
};
|
||
end = {
|
||
x: 1,
|
||
y: y
|
||
};
|
||
isVertical = false;
|
||
} else {
|
||
// y轴坐标轴
|
||
if (index) {
|
||
// 多轴的情况
|
||
var x = position === 'left' ? 0 : 1;
|
||
x = getDefaultValueFromPosition(position, x);
|
||
start = {
|
||
x: x,
|
||
y: 0
|
||
};
|
||
end = {
|
||
x: x,
|
||
y: 1
|
||
};
|
||
} else {
|
||
// 单个y轴,或者第一个y轴
|
||
var _x = position === 'right' ? 1 : 0;
|
||
|
||
_x = getDefaultValueFromPosition(position, _x);
|
||
start = {
|
||
x: _x,
|
||
y: 0
|
||
};
|
||
end = {
|
||
x: _x,
|
||
y: 1
|
||
};
|
||
}
|
||
|
||
isVertical = true;
|
||
}
|
||
|
||
start = coord.convert(start);
|
||
end = coord.convert(end);
|
||
return {
|
||
start: start,
|
||
end: end,
|
||
isVertical: isVertical
|
||
};
|
||
};
|
||
|
||
_proto._getLineCfg = function _getLineCfg(coord, scale, dimType, index) {
|
||
var factor;
|
||
|
||
var range = this._getLineRange(coord, scale, dimType, index);
|
||
|
||
var isVertical = range.isVertical; // 标识该坐标轴是否是纵坐标
|
||
|
||
var start = range.start;
|
||
var end = range.end;
|
||
var center = coord.center;
|
||
|
||
if (coord.isTransposed) {
|
||
isVertical = !isVertical;
|
||
}
|
||
|
||
if (isVertical && start.x > center.x || !isVertical && start.y > center.y) {
|
||
factor = 1;
|
||
} else {
|
||
factor = -1;
|
||
}
|
||
|
||
return {
|
||
isVertical: isVertical,
|
||
factor: factor,
|
||
start: start,
|
||
end: end
|
||
};
|
||
} // 获取圆弧坐标轴配置项信息
|
||
;
|
||
|
||
_proto._getCircleCfg = function _getCircleCfg(coord) {
|
||
var circleCfg = {};
|
||
var rangeX = coord.x;
|
||
var rangeY = coord.y;
|
||
var isReflectY = rangeY.start > rangeY.end;
|
||
var start;
|
||
|
||
if (coord.isTransposed) {
|
||
start = {
|
||
x: isReflectY ? 0 : 1,
|
||
y: 0
|
||
};
|
||
} else {
|
||
start = {
|
||
x: 0,
|
||
y: isReflectY ? 0 : 1
|
||
};
|
||
}
|
||
|
||
start = coord.convert(start);
|
||
var center = coord.circleCentre;
|
||
var startVector = [start.x - center.x, start.y - center.y];
|
||
var normalVector = [1, 0];
|
||
var startAngle;
|
||
|
||
if (start.y > center.y) {
|
||
startAngle = vec2.angle(startVector, normalVector);
|
||
} else {
|
||
startAngle = vec2.angle(startVector, normalVector) * -1;
|
||
}
|
||
|
||
var endAngle = startAngle + (rangeX.end - rangeX.start);
|
||
circleCfg.startAngle = startAngle;
|
||
circleCfg.endAngle = endAngle;
|
||
circleCfg.center = center;
|
||
circleCfg.radius = Math.sqrt(Math.pow(start.x - center.x, 2) + Math.pow(start.y - center.y, 2));
|
||
circleCfg.inner = coord.innerRadius || 0;
|
||
return circleCfg;
|
||
};
|
||
|
||
_proto._getRadiusCfg = function _getRadiusCfg(coord) {
|
||
var startAngle = coord.x.start;
|
||
var factor = startAngle < 0 ? -1 : 1;
|
||
var start;
|
||
var end;
|
||
|
||
if (coord.isTransposed) {
|
||
start = {
|
||
x: 0,
|
||
y: 0
|
||
};
|
||
end = {
|
||
x: 1,
|
||
y: 0
|
||
};
|
||
} else {
|
||
start = {
|
||
x: 0,
|
||
y: 0
|
||
};
|
||
end = {
|
||
x: 0,
|
||
y: 1
|
||
};
|
||
}
|
||
|
||
return {
|
||
factor: factor,
|
||
start: coord.convert(start),
|
||
end: coord.convert(end)
|
||
};
|
||
} // 确定坐标轴的位置
|
||
;
|
||
|
||
_proto._getAxisPosition = function _getAxisPosition(coord, dimType, index, field) {
|
||
var position = ''; // 用户自己定义了 position
|
||
|
||
var options = this.options; // const VALID_POSITIONS = [
|
||
// 'top',
|
||
// 'left',
|
||
// 'right',
|
||
// 'bottom'
|
||
// ];
|
||
|
||
if (options[field] && options[field].position) {
|
||
position = options[field].position; // if (VALID_POSITIONS.indexOf(position) > -1) {
|
||
// return position;
|
||
// }
|
||
} else {
|
||
var coordType = coord.type;
|
||
|
||
if (coord.isRect) {
|
||
if (dimType === 'x') {
|
||
position = 'bottom';
|
||
} else if (dimType === 'y') {
|
||
if (index) {
|
||
position = 'right';
|
||
} else {
|
||
position = 'left';
|
||
}
|
||
}
|
||
} else if (coordType === 'helix') {
|
||
position = 'helix';
|
||
} else if (dimType === 'x') {
|
||
position = coord.isTransposed ? 'radius' : 'circle';
|
||
} else {
|
||
position = coord.isTransposed ? 'circle' : 'radius';
|
||
}
|
||
}
|
||
|
||
return position;
|
||
} // 获取坐标轴构成的配置信息
|
||
;
|
||
|
||
_proto._getAxisDefaultCfg = function _getAxisDefaultCfg(coord, scale, type, position) {
|
||
var self = this;
|
||
var viewTheme = self.viewTheme;
|
||
var cfg = {};
|
||
var options = self.options;
|
||
var field = scale.field;
|
||
cfg = Util.deepMix({}, viewTheme.axis[position], cfg, options[field]);
|
||
cfg.viewTheme = viewTheme;
|
||
|
||
if (cfg.title) {
|
||
var title = Util.isPlainObject(cfg.title) ? cfg.title : {};
|
||
title.text = title.text || scale.alias || field;
|
||
Util.deepMix(cfg, {
|
||
title: title
|
||
});
|
||
}
|
||
|
||
cfg.ticks = scale.getTicks();
|
||
|
||
if (coord.isPolar && !scale.isCategory) {
|
||
if (type === 'x' && Math.abs(coord.endAngle - coord.startAngle) === Math.PI * 2) {
|
||
cfg.ticks.pop();
|
||
}
|
||
}
|
||
|
||
cfg.coord = coord;
|
||
|
||
if (cfg.label && Util.isNil(cfg.label.autoRotate)) {
|
||
cfg.label.autoRotate = true; // 允许自动旋转,避免重叠
|
||
}
|
||
|
||
if (options.hasOwnProperty('xField') && options.xField.hasOwnProperty('grid')) {
|
||
if (cfg.position === 'left') {
|
||
Util.deepMix(cfg, options.xField);
|
||
}
|
||
}
|
||
|
||
return cfg;
|
||
} // 确定坐标轴的配置信息
|
||
;
|
||
|
||
_proto._getAxisCfg = function _getAxisCfg(coord, scale, verticalScale, dimType, index, viewId) {
|
||
if (index === void 0) {
|
||
index = '';
|
||
}
|
||
|
||
var self = this;
|
||
|
||
var position = self._getAxisPosition(coord, dimType, index, scale.field);
|
||
|
||
var cfg = self._getAxisDefaultCfg(coord, scale, dimType, position);
|
||
|
||
if (!Util.isEmpty(cfg.grid) && verticalScale) {
|
||
// 生成 gridPoints
|
||
var gridPoints = [];
|
||
var tickValues = [];
|
||
var verticalTicks = formatTicks(verticalScale.getTicks()); // 没有垂直的坐标点时不会只栅格
|
||
|
||
if (verticalTicks.length) {
|
||
var ticks = fillAxisTicks(cfg.ticks, scale.isLinear, cfg.grid.align === 'center');
|
||
Util.each(ticks, function (tick, idx) {
|
||
tickValues.push(tick.tickValue);
|
||
var subPoints = [];
|
||
var value = tick.value;
|
||
|
||
if (cfg.grid.align === 'center') {
|
||
value = self._getMiddleValue(value, ticks, idx, scale.isLinear);
|
||
}
|
||
|
||
if (!Util.isNil(value)) {
|
||
var rangeX = coord.x;
|
||
var rangeY = coord.y;
|
||
Util.each(verticalTicks, function (verticalTick) {
|
||
var x = dimType === 'x' ? value : verticalTick.value;
|
||
var y = dimType === 'x' ? verticalTick.value : value;
|
||
var point = coord.convert({
|
||
x: x,
|
||
y: y
|
||
});
|
||
|
||
if (coord.isPolar) {
|
||
var center = coord.circleCentre;
|
||
|
||
if (rangeY.start > rangeY.end) {
|
||
y = 1 - y;
|
||
}
|
||
|
||
point.flag = rangeX.start > rangeX.end ? 0 : 1;
|
||
point.radius = Math.sqrt(Math.pow(point.x - center.x, 2) + Math.pow(point.y - center.y, 2));
|
||
}
|
||
|
||
subPoints.push(point);
|
||
});
|
||
gridPoints.push({
|
||
_id: viewId + '-' + dimType + index + '-grid-' + tick.tickValue,
|
||
points: subPoints
|
||
});
|
||
}
|
||
});
|
||
}
|
||
|
||
cfg.grid.items = gridPoints;
|
||
cfg.grid.tickValues = tickValues;
|
||
}
|
||
|
||
cfg.type = scale.type;
|
||
return cfg;
|
||
};
|
||
|
||
_proto._getHelixCfg = function _getHelixCfg(coord) {
|
||
var helixCfg = {};
|
||
var a = coord.a;
|
||
var startAngle = coord.startAngle;
|
||
var endAngle = coord.endAngle;
|
||
var index = 100;
|
||
var crp = [];
|
||
|
||
for (var i = 0; i <= index; i++) {
|
||
var point = coord.convert({
|
||
x: i / 100,
|
||
y: 0
|
||
});
|
||
crp.push(point.x);
|
||
crp.push(point.y);
|
||
}
|
||
|
||
var axisStart = coord.convert({
|
||
x: 0,
|
||
y: 0
|
||
});
|
||
helixCfg.a = a;
|
||
helixCfg.startAngle = startAngle;
|
||
helixCfg.endAngle = endAngle;
|
||
helixCfg.crp = crp;
|
||
helixCfg.axisStart = axisStart;
|
||
helixCfg.center = coord.center;
|
||
helixCfg.inner = coord.y.start; // 内半径
|
||
|
||
return helixCfg;
|
||
};
|
||
|
||
_proto._drawAxis = function _drawAxis(coord, scale, verticalScale, dimType, viewId, xAxis, index) {
|
||
var container = this.container;
|
||
var canvas = this.canvas;
|
||
var C; // 坐标轴类
|
||
|
||
var appendCfg; // 每个坐标轴 start end 等绘制边界的信息
|
||
|
||
if (coord.type === 'cartesian') {
|
||
C = Axis.Line;
|
||
appendCfg = this._getLineCfg(coord, scale, dimType, index);
|
||
} else if (coord.type === 'helix' && dimType === 'x') {
|
||
C = Axis.Helix;
|
||
appendCfg = this._getHelixCfg(coord);
|
||
} else if (dimType === 'x') {
|
||
C = Axis.Circle;
|
||
appendCfg = this._getCircleCfg(coord);
|
||
} else {
|
||
C = Axis.Line;
|
||
appendCfg = this._getRadiusCfg(coord);
|
||
}
|
||
|
||
var cfg = this._getAxisCfg(coord, scale, verticalScale, dimType, index, viewId);
|
||
|
||
cfg = Util.mix({}, cfg, appendCfg);
|
||
|
||
if (dimType === 'y' && xAxis && xAxis.get('type') === 'circle') {
|
||
cfg.circle = xAxis;
|
||
}
|
||
|
||
cfg._id = viewId + '-' + dimType;
|
||
|
||
if (!Util.isNil(index)) {
|
||
cfg._id = viewId + '-' + dimType + index;
|
||
}
|
||
|
||
Util.mix(cfg, {
|
||
canvas: canvas,
|
||
// 每个 axis 需要单独的 group,
|
||
// 否则所有的 aixs 的文本都混在一起了
|
||
// 同时无法知道是哪个坐标轴的事件
|
||
group: container.addGroup({
|
||
viewId: viewId
|
||
})
|
||
});
|
||
var axis = new C(cfg);
|
||
axis.render();
|
||
this.axes.push(axis);
|
||
return axis;
|
||
};
|
||
|
||
_proto.createAxis = function createAxis(xScale, yScales, viewId) {
|
||
var self = this;
|
||
var coord = this.coord;
|
||
var coordType = coord.type; // theta坐标系默认不绘制坐标轴
|
||
|
||
if (coordType !== 'theta' && !(coordType === 'polar' && coord.isTransposed)) {
|
||
var xAxis;
|
||
|
||
if (xScale && !self._isHide(xScale.field)) {
|
||
xAxis = self._drawAxis(coord, xScale, yScales[0], 'x', viewId); // 绘制 x 轴
|
||
}
|
||
|
||
if (!Util.isEmpty(yScales) && coordType !== 'helix') {
|
||
Util.each(yScales, function (yScale, index) {
|
||
if (!self._isHide(yScale.field)) {
|
||
self._drawAxis(coord, yScale, xScale, 'y', viewId, xAxis, index);
|
||
}
|
||
});
|
||
}
|
||
}
|
||
};
|
||
|
||
_proto.changeVisible = function changeVisible(visible) {
|
||
var axes = this.axes;
|
||
Util.each(axes, function (axis) {
|
||
axis.set('visible', visible);
|
||
});
|
||
};
|
||
|
||
_proto.clear = function clear() {
|
||
var self = this;
|
||
var axes = self.axes;
|
||
Util.each(axes, function (axis) {
|
||
axis.destroy();
|
||
});
|
||
self.axes = [];
|
||
};
|
||
|
||
return AxisController;
|
||
}();
|
||
|
||
module.exports = AxisController; |