@antv/g2plot
Version:
G2 Plot, a market of plots built with the Grammar of Graphics'
219 lines • 7.8 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
var tslib_1 = require("tslib");
var g_1 = require("@antv/g");
var g2_1 = require("@antv/g2");
var _ = tslib_1.__importStar(require("@antv/util"));
var DEFAULT_SIZE = 12;
var TOLERANCE = 0.01;
var MAX_ITERATION = 100;
var MIN_HEIGHT = 12;
function getRange(points) {
var maxHeight = -Infinity;
var min = Infinity;
var max = -Infinity;
_.each(points, function (p) {
min = Math.min(p.x, min);
max = Math.max(p.x, max);
var height = Math.abs(p.y[0] - p.y[1]);
maxHeight = Math.max(maxHeight, height);
});
return {
xRange: [min, max],
maxHeight: maxHeight,
};
}
function interpolateY(x, points, index) {
var leftPoint = points[0];
var rightPoint = points[points.length - 1];
_.each(points, function (p) {
if (p.x === x) {
return p.y[index];
}
if (p.x < x && p.x > leftPoint.x) {
leftPoint = p;
}
if (p.x > x && p.x < rightPoint.x) {
rightPoint = p;
}
});
var t = (x - leftPoint.x) / (rightPoint.x - leftPoint.x);
return leftPoint.y[index] * (1 - t) + rightPoint.y[index] * t;
}
function getXIndex(data, x) {
// tslint:disable-next-line: prefer-for-of
var i;
for (i = 0; i < data.length; i++) {
var d = data[i];
if (d.x === x || d.x > x) {
break;
}
}
return i;
}
var AreaLabel = /** @class */ (function (_super) {
tslib_1.__extends(AreaLabel, _super);
function AreaLabel() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.scaleFactor = [];
return _this;
}
AreaLabel.prototype.showLabels = function (points, shapes) {
var _this = this;
// 获取堆叠字段
var stackField = this.get('element').get('attrs').color.scales[0].field;
// 根据stackField将point分组
var groupedPoints = this._groupPoints(points, stackField);
var labelPoints = [];
_.each(groupedPoints, function (pointArray, name) {
var labelPoint = _this._drawLabel(pointArray, name);
if (labelPoint) {
labelPoints.push(_.mix({}, pointArray[0], labelPoint));
_this.scaleFactor.push(labelPoint.scaleFactor);
}
});
_super.prototype.showLabels.call(this, labelPoints, shapes);
var labelOptions = this.get('labelOptions');
if (labelOptions.autoScale) {
this._adjuestLabelSize();
}
};
AreaLabel.prototype._groupPoints = function (points, field) {
var groupedPoints = {};
_.each(points, function (p) {
var value = p._origin[field];
if (!_.has(groupedPoints, value)) {
groupedPoints[value] = [];
}
groupedPoints[value].push(p);
});
return groupedPoints;
};
AreaLabel.prototype._drawLabel = function (points, name) {
var _a = getRange(points), xRange = _a.xRange, maxHeight = _a.maxHeight;
// 根据area宽度在x方向各点间做插值
var resolution = xRange[1] - xRange[0];
var interpolatedPoints = this._getInterpolatedPoints(xRange[0], resolution, points);
// 获取label的bbox
var bbox = this._getLabelBbox(name);
var fitOption = {
xRange: xRange,
aspect: bbox.width / bbox.height,
data: interpolatedPoints,
justTest: true,
};
var height = this._bisection(MIN_HEIGHT, maxHeight, this._testFit, fitOption, TOLERANCE, MAX_ITERATION);
if (height === null) {
return;
}
fitOption.justTest = false;
var fit = this._testFit(fitOption);
fit.x = fit.x;
fit.y = fit.y0 + (fit.y1 - fit.y0) / 2;
fit.scaleFactor = (height / bbox.height) * 0.4;
return fit;
};
AreaLabel.prototype._getInterpolatedPoints = function (minX, resolution, points) {
var interpolatedPoints = [];
var step = 2;
for (var i = minX; i < resolution; i += step) {
var y0 = interpolateY(i, points, 0);
var y1 = interpolateY(i, points, 1);
interpolatedPoints.push({
x: i,
y: [y0, y1],
});
}
return interpolatedPoints;
};
AreaLabel.prototype._bisection = function (min, max, test, testOption, tolerance, maxIteration) {
for (var i = 0; i < maxIteration; i++) {
var middle = (min + max) / 2;
var options = testOption;
options.height = middle;
options.width = middle * options.aspect;
var passesTest = test(options);
var withinTolerance = (max - min) / 2 < tolerance;
if (passesTest && withinTolerance) {
return middle;
}
if (passesTest) {
min = middle;
}
else {
max = middle;
}
}
return null;
};
AreaLabel.prototype._testFit = function (option) {
var xRange = option.xRange, width = option.width, height = option.height, data = option.data, justTest = option.justTest;
for (var i = 0; i < data.length; i++) {
var d = data[i];
var x0 = d.x;
var x1 = x0 + width;
if (x1 > xRange[1]) {
break;
}
var x1_index = getXIndex(data, x1);
var ceiling = -Infinity;
var ceilingFloor = null; // 保存ceiling时对应的bottom位置,ceil和floor不一定是一对坐标
var floor = Infinity;
for (var j = i; j < x1_index; j++) {
var top_1 = data[j].y[1];
var bottom = data[j].y[0];
if (bottom < floor) {
floor = bottom;
}
if (top_1 > ceiling) {
ceiling = top_1;
ceilingFloor = bottom;
}
if (floor - ceiling < height) {
break;
}
}
if (floor - ceiling >= height) {
if (justTest) {
return true;
}
return {
x: x0,
y0: ceiling,
y1: ceilingFloor,
width: width,
height: height,
};
}
}
return false;
};
AreaLabel.prototype._getLabelBbox = function (text) {
var plot = this.get('labelOptions').plot;
var labelStyle = _.clone(plot.theme.label.textStyle);
labelStyle.fontSize = DEFAULT_SIZE;
var tShape = new g_1.Text({
attrs: tslib_1.__assign({ text: text, x: 0, y: 0 }, labelStyle),
});
return tShape.getBBox();
};
AreaLabel.prototype._adjuestLabelSize = function () {
var _this = this;
var renderer = this.get('labelsRenderer');
var labels = renderer.get('group').get('children');
var view = this.get('element').get('view');
_.each(labels, function (label, index) {
var scaleFactor = _this.scaleFactor[index];
label.attr('fontSize', DEFAULT_SIZE);
label.transform([
['t', -label.attr('x'), -label.attr('y')],
['s', scaleFactor, scaleFactor],
['t', label.attr('x'), label.attr('y')],
]);
});
view.get('canvas').draw();
};
return AreaLabel;
}(g2_1.ElementLabels));
g2_1.registerElementLabels('area', AreaLabel);
//# sourceMappingURL=area-label.js.map