/** * @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;