UNPKG

@antv/g2

Version:

the Grammar of Graphics in Javascript

222 lines 9.58 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.pieOuterLabelLayout = void 0; var tslib_1 = require("tslib"); var util_1 = require("@antv/util"); var graphics_1 = require("../../../../util/graphics"); var util_2 = require("./util"); /** label text和line距离 4px */ var MARGIN = 4; /** * 配置 labelline * @param item PolarLabelItem */ function drawLabelline(item /** PolarLabelItem */, coordinate) { /** 坐标圆心 */ var center = coordinate.getCenter(); /** 圆半径 */ var radius = coordinate.getRadius(); if (item && item.labelLine) { var angle = item.angle, labelOffset = item.offset; // 贴近圆周 var startPoint = (0, graphics_1.polarToCartesian)(center.x, center.y, radius, angle); var itemX = item.x + (0, util_1.get)(item, 'offsetX', 0) * (Math.cos(angle) > 0 ? 1 : -1); var itemY = item.y + (0, util_1.get)(item, 'offsetY', 0) * (Math.sin(angle) > 0 ? 1 : -1); var endPoint = { x: itemX - Math.cos(angle) * MARGIN, y: itemY - Math.sin(angle) * MARGIN, }; var smoothConnector = item.labelLine.smooth; var path = []; var dx = endPoint.x - center.x; var dy = endPoint.y - center.y; var endAngle = Math.atan(dy / dx); // 第三象限 & 第四象限 if (dx < 0) { endAngle += Math.PI; } // 默认 smooth, undefined 也为 smooth if (smoothConnector === false) { if (!(0, util_1.isObject)(item.labelLine)) { // labelLine: true item.labelLine = {}; } // 表示弧线的方向,0 表示从起点到终点沿逆时针画弧, 1 表示顺时针 var sweepFlag = 0; // 第一象限 if ((angle < 0 && angle > -Math.PI / 2) || angle > Math.PI * 1.5) { if (endPoint.y > startPoint.y) { sweepFlag = 1; } } // 第二象限 if (angle >= 0 && angle < Math.PI / 2) { if (endPoint.y > startPoint.y) { sweepFlag = 1; } } // 第三象限 if (angle >= Math.PI / 2 && angle < Math.PI) { if (startPoint.y > endPoint.y) { sweepFlag = 1; } } // 第四象限 if (angle < -Math.PI / 2 || (angle >= Math.PI && angle < Math.PI * 1.5)) { if (startPoint.y > endPoint.y) { sweepFlag = 1; } } var distance = labelOffset / 2 > 4 ? 4 : Math.max(labelOffset / 2 - 1, 0); var breakPoint = (0, graphics_1.polarToCartesian)(center.x, center.y, radius + distance, angle); // 圆弧的结束点 var breakPoint3 = (0, graphics_1.polarToCartesian)(center.x, center.y, radius + labelOffset / 2, endAngle); /** * @example * M 100 100 L100 90 A 50 50 0 0 0 150 50 * 移动至 (100, 100), 连接到 (100, 90), 以 (50, 50) 为圆心,绘制圆弧至 (150, 50); * A 命令的第 4 个参数 large-arc-flag, 决定弧线是大于还是小于 180 度: 0 表示小角度弧,1 表示大角 * 第 5 个参数: 是否顺时针绘制 */ // 默认小弧 var largeArcFlag = 0; // step1: 移动至起点 path.push("M ".concat(startPoint.x, " ").concat(startPoint.y)); // step2: 连接拐点 path.push("L ".concat(breakPoint.x, " ").concat(breakPoint.y)); // step3: 绘制圆弧 至 结束点 path.push("A ".concat(center.x, " ").concat(center.y, " 0 ").concat(largeArcFlag, " ").concat(sweepFlag, " ").concat(breakPoint3.x, " ").concat(breakPoint3.y)); // step4: 连接结束点 path.push("L ".concat(endPoint.x, " ").concat(endPoint.y)); } else { var breakPoint = (0, graphics_1.polarToCartesian)(center.x, center.y, radius + (labelOffset / 2 > 4 ? 4 : Math.max(labelOffset / 2 - 1, 0)), angle); // G2 旧的拉线 // path.push('Q', `${breakPoint.x}`, `${breakPoint.y}`, `${endPoint.x}`, `${endPoint.y}`); var xSign = startPoint.x < center.x ? 1 : -1; // step1: 连接结束点 path.push("M ".concat(endPoint.x, " ").concat(endPoint.y)); var slope1 = (startPoint.y - center.y) / (startPoint.x - center.x); var slope2 = (endPoint.y - center.y) / (endPoint.x - center.x); if (Math.abs(slope1 - slope2) > Math.pow(Math.E, -16)) { // step2: 绘制 curve line (起点 & 结合点与圆心的斜率不等时, 由于存在误差, 使用近似处理) path.push.apply(path, [ 'C', endPoint.x + xSign * 4, endPoint.y, 2 * breakPoint.x - startPoint.x, 2 * breakPoint.y - startPoint.y, startPoint.x, startPoint.y, ]); } // step3: 连接至起点 path.push("L ".concat(startPoint.x, " ").concat(startPoint.y)); } item.labelLine.path = path.join(' '); } } /** * 饼图 outer-label 布局, 适用于 type = pie 且 label offset > 0 的标签 */ function pieOuterLabelLayout(originalItems, labels, shapes, region) { var e_1, _a; var items = (0, util_1.filter)(originalItems, function (item) { return !(0, util_1.isNil)(item); }); /** 坐标系 */ var coordinate = labels[0] && labels[0].get('coordinate'); if (!coordinate) { return; } /** 坐标圆心 */ var center = coordinate.getCenter(); /** 圆半径 */ var radius = coordinate.getRadius(); /** label shapes */ var labelsMap = {}; try { for (var labels_1 = tslib_1.__values(labels), labels_1_1 = labels_1.next(); !labels_1_1.done; labels_1_1 = labels_1.next()) { var labelShape = labels_1_1.value; labelsMap[labelShape.get('id')] = labelShape; } } catch (e_1_1) { e_1 = { error: e_1_1 }; } finally { try { if (labels_1_1 && !labels_1_1.done && (_a = labels_1.return)) _a.call(labels_1); } finally { if (e_1) throw e_1.error; } } // note labelHeight 可以控制 label 的行高 var labelHeight = (0, util_1.get)(items[0], 'labelHeight', 14); var labelOffset = (0, util_1.get)(items[0], 'offset', 0); if (labelOffset <= 0) { return; } var LEFT_HALF_KEY = 'left'; var RIGHT_HALF_KEY = 'right'; // step 1: separate labels var separateLabels = (0, util_1.groupBy)(items, function (item) { return (item.x < center.x ? LEFT_HALF_KEY : RIGHT_HALF_KEY); }); var start = coordinate.start, end = coordinate.end; // step2: calculate totalHeight var totalHeight = Math.min((radius + labelOffset + labelHeight) * 2, coordinate.getHeight()); var totalR = totalHeight / 2; /** labels 容器的范围(后续根据组件的布局设计进行调整) */ var labelsContainerRange = { minX: start.x, maxX: end.x, minY: center.y - totalR, maxY: center.y + totalR, }; // step 3: antiCollision (0, util_1.each)(separateLabels, function (half, key) { var maxLabelsCountForOneSide = Math.floor(totalHeight / labelHeight); if (half.length > maxLabelsCountForOneSide) { half.sort(function (a, b) { // sort by percentage DESC return b.percent - a.percent; }); (0, util_1.each)(half, function (labelItem, idx) { if (idx + 1 > maxLabelsCountForOneSide) { labelsMap[labelItem.id].set('visible', false); labelItem.invisible = true; } }); } (0, util_2.antiCollision)(half, labelHeight, labelsContainerRange); }); (0, util_1.each)(separateLabels, function (half, key) { (0, util_1.each)(half, function (item) { var isRight = key === RIGHT_HALF_KEY; var labelShape = labelsMap[item.id]; // because group could not effect content-shape, should set content-shape position manually var content = labelShape.getChildByIndex(0); // textShape 发生过调整 if (content) { var r = radius + labelOffset; // (x - cx)^2 + (y - cy)^2 = totalR^2 var dy = item.y - center.y; var rPow2 = Math.pow(r, 2); var dyPow2 = Math.pow(dy, 2); var dxPow2 = rPow2 - dyPow2 > 0 ? rPow2 - dyPow2 : 0; var dx = Math.sqrt(dxPow2); var dx_offset = Math.abs(Math.cos(item.angle) * r); if (!isRight) { // left item.x = center.x - Math.max(dx, dx_offset); } else { // right item.x = center.x + Math.max(dx, dx_offset); } } // adjust labelShape if (content) { content.attr('y', item.y); content.attr('x', item.x); } drawLabelline(item, coordinate); }); }); } exports.pieOuterLabelLayout = pieOuterLabelLayout; //# sourceMappingURL=outer.js.map