@antv/f2
Version:
Charts for mobile visualization.
358 lines (357 loc) • 12.4 kB
JavaScript
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2";
import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray";
import _classCallCheck from "@babel/runtime/helpers/esm/classCallCheck";
import _createClass from "@babel/runtime/helpers/esm/createClass";
import _inherits from "@babel/runtime/helpers/esm/inherits";
import _createSuper from "@babel/runtime/helpers/esm/createSuper";
import { jsx } from '../../jsx';
import Component from '../../base/component';
import { deepMix, isArray, isFunction } from '@antv/util';
import { isInBBox, getElementsByClassName } from '../../util';
var DEFAULT_CONFIG = {
anchorOffset: '10px',
inflectionOffset: '30px',
sidePadding: '15px',
height: '64px',
adjustOffset: '30',
triggerOn: 'click',
// activeShape: false, // 当有图形被选中的时候,是否激活图形
// activeStyle: {
// offset: '1px',
// appendRadius: '8px',
// fillOpacity: 0.5,
// },
label1OffsetY: '-4px',
label2OffsetY: '4px'
};
function getEndPoint(center, angle, r) {
return {
x: center.x + r * Math.cos(angle),
y: center.y + r * Math.sin(angle)
};
}
// 计算中间角度
function getMiddleAngle(startAngle, endAngle) {
if (endAngle < startAngle) {
endAngle += Math.PI * 2;
}
return (endAngle + startAngle) / 2;
}
function move(from, to, count, center) {
var x = center.x;
var sort = from.sort(function (a, b) {
var aDistance = Math.abs(a.x - x);
var bDistance = Math.abs(b.x - x);
return bDistance - aDistance;
});
return [sort.slice(0, sort.length - count), sort.slice(sort.length - count).concat(to)];
}
// 第一象限
function isFirstQuadrant(angle) {
return angle >= -Math.PI / 2 && angle < 0;
}
// 第二象限
function isSecondQuadrant(angle) {
return angle >= 0 && angle < Math.PI / 2;
}
function isThirdQuadrant(angle) {
return angle >= Math.PI / 2 && angle < Math.PI;
}
function isFourthQuadrant(angle) {
return angle >= Math.PI && angle < Math.PI * 3 / 2;
}
function findShapeByClassName(shape, point, className) {
var targetShapes = getElementsByClassName(className, shape);
for (var i = 0, len = targetShapes.length; i < len; i++) {
var _shape = targetShapes[i];
if (isInBBox(_shape.getBBox(), point)) {
return _shape;
}
}
}
export default (function (View) {
return /*#__PURE__*/function (_Component) {
_inherits(PieLabel, _Component);
var _super = _createSuper(PieLabel);
function PieLabel(props) {
var _this;
_classCallCheck(this, PieLabel);
_this = _super.call(this, props);
_this._handleEvent = function (ev) {
var _this$props = _this.props,
chart = _this$props.chart,
onClick = _this$props.onClick;
var ele = _this.triggerRef.current;
var point = ev.points[0];
var shape = findShapeByClassName(ele, point, 'click');
var pieData = chart.getSnapRecords(point);
if (typeof onClick === 'function') {
// 点击label
if (shape) {
onClick(shape.get('data'));
}
// 点击饼图
else if (isArray(pieData) && pieData.length > 0) {
onClick(pieData);
}
}
};
_this.triggerRef = {};
return _this;
}
_createClass(PieLabel, [{
key: "willMount",
value: function willMount() {}
/**
* 绑定事件
*/
}, {
key: "didMount",
value: function didMount() {
this._initEvent();
}
}, {
key: "getLabels",
value: function getLabels(props) {
var chart = props.chart,
coord = props.coord,
anchorOffset = props.anchorOffset,
inflectionOffset = props.inflectionOffset,
label1 = props.label1,
label2 = props.label2,
itemHeight = props.height,
sidePadding = props.sidePadding;
var center = coord.center,
radius = coord.radius,
coordWidth = coord.width,
coordHeight = coord.height,
coordLeft = coord.left,
coordRight = coord.right,
coordTop = coord.top;
var maxCountForOneSide = Math.floor(coordHeight / itemHeight);
var maxCount = maxCountForOneSide * 2;
var geometry = chart.getGeometrys()[0];
var records = geometry.flatRecords()
// 按角度大到小排序
.sort(function (a, b) {
var angle1 = a.xMax - a.xMin;
var angle2 = b.xMax - b.xMin;
return angle2 - angle1;
})
// 只取前 maxCount 个显示
.slice(0, maxCount);
// 存储左右 labels
var halves = [[], [] // right
];
records.forEach(function (record) {
var xMin = record.xMin,
xMax = record.xMax,
color = record.color,
origin = record.origin;
// 锚点角度
var anchorAngle = getMiddleAngle(xMin, xMax);
// 锚点坐标
var anchorPoint = getEndPoint(center, anchorAngle, radius + anchorOffset);
// 拐点坐标
var inflectionPoint = getEndPoint(center, anchorAngle, radius + inflectionOffset);
// 锚点方向
var side = anchorPoint.x < center.x ? 'left' : 'right';
var label = {
origin: origin,
angle: anchorAngle,
anchor: anchorPoint,
inflection: inflectionPoint,
side: side,
x: inflectionPoint.x,
y: inflectionPoint.y,
r: radius + inflectionOffset,
color: color,
label1: isFunction(label1) ? label1(origin, record) : label1,
label2: isFunction(label2) ? label2(origin, record) : label2
};
// 判断文本的方向
if (side === 'left') {
halves[0].push(label);
} else {
halves[1].push(label);
}
});
// 判断是有一边超过了显示的最大
if (halves[0].length > maxCountForOneSide) {
halves = move(halves[0], halves[1], halves[0].length - maxCountForOneSide, center);
} else if (halves[1].length > maxCountForOneSide) {
var _move = move(halves[1], halves[0], halves[1].length - maxCountForOneSide, center),
_move2 = _slicedToArray(_move, 2),
right = _move2[0],
left = _move2[1];
halves = [left, right];
}
// label 的最大宽度
var labelWidth = coordWidth / 2 - radius - anchorOffset - inflectionOffset - 2 * sidePadding;
var labels = [];
halves.forEach(function (half, index) {
var showSide = index === 0 ? 'left' : 'right';
// 顺时针方向排序
half.sort(function (a, b) {
var aAngle = a.angle;
var bAngle = b.angle;
if (showSide === 'left') {
// 是否在第一象限
aAngle = isFirstQuadrant(aAngle) ? aAngle + Math.PI * 2 : aAngle;
bAngle = isFirstQuadrant(bAngle) ? bAngle + Math.PI * 2 : bAngle;
return bAngle - aAngle;
} else {
// 是否在第四象限
aAngle = isFourthQuadrant(aAngle) ? aAngle - Math.PI * 2 : aAngle;
bAngle = isFourthQuadrant(bAngle) ? bAngle - Math.PI * 2 : bAngle;
return aAngle - bAngle;
}
});
var pointsY = half.map(function (label) {
return label.y;
});
var maxY = Math.max.apply(null, pointsY);
var minY = Math.min.apply(null, pointsY);
// 每个 label 占用的高度
var labelCount = half.length;
var labelHeight = coordHeight / labelCount;
var halfLabelHeight = labelHeight / 2;
// 线之间的间隔
var lineInterval = 2;
if (showSide === 'left') {
half.forEach(function (label, index) {
var anchor = label.anchor,
inflection = label.inflection,
angle = label.angle,
x = label.x,
y = label.y;
var points = [anchor, inflection];
var endX = coordLeft + sidePadding;
var endY = coordTop + halfLabelHeight + labelHeight * index;
// 文本开始点
var labelStart = {
x: endX + labelWidth + lineInterval * index,
y: endY
};
// 文本结束点
var labelEnd = {
x: endX,
y: endY
};
// 第四象限
if (isFirstQuadrant(angle)) {
var pointY = minY - lineInterval * (labelCount - index);
points.push({
x: x,
y: pointY
});
points.push({
x: labelStart.x,
y: pointY
});
} else if (isThirdQuadrant(angle) || isFourthQuadrant(angle)) {
points.push({
x: labelStart.x,
y: y
});
} else if (isSecondQuadrant(angle)) {
var _pointY = maxY + lineInterval * index;
points.push({
x: x,
y: _pointY
});
points.push({
x: labelStart.x,
y: _pointY
});
}
points.push(labelStart);
points.push(labelEnd);
label.points = points;
label.side = showSide;
labels.push(label);
});
} else {
half.forEach(function (label, index) {
var anchor = label.anchor,
inflection = label.inflection,
angle = label.angle,
x = label.x,
y = label.y;
// 折线的点
var points = [anchor, inflection];
var endX = coordRight - sidePadding;
var endY = coordTop + halfLabelHeight + labelHeight * index;
// 文本开始点
var labelStart = {
x: endX - labelWidth - lineInterval * index,
y: endY
};
// 文本结束点
var labelEnd = {
x: endX,
y: endY
};
// 第四象限
if (isFourthQuadrant(angle)) {
var pointY = minY - lineInterval * (labelCount - index);
points.push({
x: x,
y: pointY
});
points.push({
x: labelStart.x,
y: pointY
});
} else if (isFirstQuadrant(angle) || isSecondQuadrant(angle)) {
points.push({
x: labelStart.x,
y: y
});
} else if (isThirdQuadrant(angle)) {
var _pointY2 = maxY + lineInterval * index;
points.push({
x: x,
y: _pointY2
});
points.push({
x: labelStart.x,
y: _pointY2
});
}
points.push(labelStart);
points.push(labelEnd);
label.points = points;
label.side = showSide;
labels.push(label);
});
}
});
return labels;
}
}, {
key: "_initEvent",
value: function _initEvent() {
var context = this.context,
props = this.props;
var canvas = context.canvas;
var _props$triggerOn = props.triggerOn,
triggerOn = _props$triggerOn === void 0 ? DEFAULT_CONFIG.triggerOn : _props$triggerOn;
canvas.on(triggerOn, this._handleEvent);
}
}, {
key: "render",
value: function render() {
var context = this.context;
var props = context.px2hd(deepMix({}, DEFAULT_CONFIG, this.props));
var labels = this.getLabels(props);
return jsx(View, _objectSpread(_objectSpread({
labels: labels
}, props), {}, {
triggerRef: this.triggerRef
}));
}
}]);
return PieLabel;
}(Component);
});