devextreme
Version:
HTML5 JavaScript Component Suite for Responsive Web Development
372 lines (370 loc) • 14.7 kB
JavaScript
/**
* DevExtreme (cjs/viz/series/points/pie_point.js)
* Version: 24.2.6
* Build date: Mon Mar 17 2025
*
* Copyright (c) 2012 - 2025 Developer Express Inc. ALL RIGHTS RESERVED
* Read about DevExtreme licensing here: https://js.devexpress.com/Licensing/
*/
"use strict";
exports.default = void 0;
var _extend2 = require("../../../core/utils/extend");
var _symbol_point = _interopRequireDefault(require("./symbol_point"));
var _utils = require("../../core/utils");
var _type = require("../../../core/utils/type");
var _consts = _interopRequireDefault(require("../../components/consts"));
function _interopRequireDefault(e) {
return e && e.__esModule ? e : {
default: e
}
}
const _extend = _extend2.extend;
const _round = Math.round;
const _sqrt = Math.sqrt;
const _acos = Math.acos;
const DEG = 180 / Math.PI;
const _abs = Math.abs;
const RADIAL_LABEL_INDENT = _consts.default.radialLabelIndent;
var _default = exports.default = _extend({}, _symbol_point.default, {
_updateData: function(data, argumentChanged) {
const that = this;
_symbol_point.default._updateData.call(this, data);
if (argumentChanged || !(0, _type.isDefined)(that._visible)) {
that._visible = true
}
that.minValue = that.initialMinValue = that.originalMinValue = (0, _type.isDefined)(data.minValue) ? data.minValue : 0
},
animate: function(complete, duration, delay) {
this.graphic.animate({
x: this.centerX,
y: this.centerY,
outerRadius: this.radiusOuter,
innerRadius: this.radiusInner,
startAngle: this.toAngle,
endAngle: this.fromAngle
}, {
delay: delay,
partitionDuration: duration
}, complete)
},
correctPosition: function(correction) {
this.correctRadius(correction);
this.correctLabelRadius(correction.radiusOuter + RADIAL_LABEL_INDENT);
this.centerX = correction.centerX;
this.centerY = correction.centerY
},
correctRadius: function(correction) {
this.radiusInner = correction.radiusInner;
this.radiusOuter = correction.radiusOuter
},
correctLabelRadius: function(radiusLabels) {
this.radiusLabels = radiusLabels
},
correctValue: function(correction, percent, base) {
this.value = (base || this.normalInitialValue) + correction;
this.minValue = correction;
this.percent = percent;
this._label.setDataField("percent", percent)
},
_updateLabelData: function() {
this._label.setData(this._getLabelFormatObject())
},
_getShiftLabelCoords: function() {
const that = this;
const bBox = that._label.getBoundingRect();
const coord = that._getLabelCoords(that._label);
const visibleArea = that._getVisibleArea();
if (that._isLabelDrawingWithoutPoints) {
return that._checkLabelPosition(coord, bBox, visibleArea)
} else {
return that._getLabelExtraCoord(coord, that._checkVerticalLabelPosition(coord, bBox, visibleArea), bBox)
}
},
_getLabelPosition: function(options) {
return options.position
},
getAnnotationCoords: function(location) {
return this._getElementCoords("edge" !== location ? "inside" : "outside", this.radiusOuter, 0)
},
_getElementCoords: function(position, elementRadius, radialOffset) {
let bBox = arguments.length > 3 && void 0 !== arguments[3] ? arguments[3] : {
x: 0,
y: 0,
width: 0,
height: 0
};
const that = this;
const angleFunctions = (0, _utils.getCosAndSin)(that.middleAngle);
const radiusInner = that.radiusInner;
const radiusOuter = that.radiusOuter;
const columnsPosition = "columns" === position;
let rad;
let x;
if ("inside" === position) {
rad = radiusInner + (radiusOuter - radiusInner) / 2 + radialOffset;
x = that.centerX + rad * angleFunctions.cos - bBox.width / 2
} else {
rad = elementRadius + radialOffset;
if (angleFunctions.cos > .1 || columnsPosition && angleFunctions.cos >= 0) {
x = that.centerX + rad * angleFunctions.cos
} else if (angleFunctions.cos < -.1 || columnsPosition && angleFunctions.cos < 0) {
x = that.centerX + rad * angleFunctions.cos - bBox.width
} else {
x = that.centerX + rad * angleFunctions.cos - bBox.width / 2
}
}
return {
x: x,
y: _round(that.centerY - rad * angleFunctions.sin - bBox.height / 2)
}
},
_getLabelCoords: function(label) {
const bBox = label.getBoundingRect();
const options = label.getLayoutOptions();
const position = this._getLabelPosition(options);
return this._getElementCoords(position, this.radiusLabels, options.radialOffset, bBox)
},
_correctLabelCoord: function(coord, moveLabelsFromCenter) {
const label = this._label;
const bBox = label.getBoundingRect();
const labelWidth = bBox.width;
const options = label.getLayoutOptions();
const visibleArea = this._getVisibleArea();
const rightBorderX = visibleArea.maxX - labelWidth;
const leftBorderX = visibleArea.minX;
const angleOfPoint = (0, _utils.normalizeAngle)(this.middleAngle);
const centerX = this.centerX;
const connectorOffset = options.connectorOffset;
let x = coord.x;
if ("columns" === options.position) {
if (angleOfPoint <= 90 || angleOfPoint >= 270) {
x = rightBorderX
} else {
x = leftBorderX
}
coord.x = x
} else if ("inside" !== options.position && moveLabelsFromCenter) {
if (angleOfPoint <= 90 || angleOfPoint >= 270) {
if (x - connectorOffset < centerX) {
x = centerX + connectorOffset
}
} else if (x + labelWidth + connectorOffset > centerX) {
x = centerX - labelWidth - connectorOffset
}
coord.x = x
}
return coord
},
drawLabel: function() {
this.translate();
this._isLabelDrawingWithoutPoints = true;
this._drawLabel();
this._isLabelDrawingWithoutPoints = false
},
updateLabelCoord: function(moveLabelsFromCenter) {
const bBox = this._label.getBoundingRect();
let coord = this._correctLabelCoord(bBox, moveLabelsFromCenter);
coord = this._checkHorizontalLabelPosition(coord, bBox, this._getVisibleArea());
this._label.shift(_round(coord.x), _round(bBox.y))
},
_checkVerticalLabelPosition: function(coord, box, visibleArea) {
const x = coord.x;
let y = coord.y;
if (coord.y + box.height > visibleArea.maxY) {
y = visibleArea.maxY - box.height
} else if (coord.y < visibleArea.minY) {
y = visibleArea.minY
}
return {
x: x,
y: y
}
},
_getLabelExtraCoord: function(coord, shiftCoord, box) {
return coord.y !== shiftCoord.y ? (0, _utils.getVerticallyShiftedAngularCoords)({
x: coord.x,
y: coord.y,
width: box.width,
height: box.height
}, shiftCoord.y - coord.y, {
x: this.centerX,
y: this.centerY
}) : coord
},
_checkHorizontalLabelPosition: function(coord, box, visibleArea) {
let x = coord.x;
const y = coord.y;
if (coord.x + box.width > visibleArea.maxX) {
x = visibleArea.maxX - box.width
} else if (coord.x < visibleArea.minX) {
x = visibleArea.minX
}
return {
x: x,
y: y
}
},
applyWordWrap: function(moveLabelsFromCenter) {
const that = this;
const label = that._label;
const box = label.getBoundingRect();
const visibleArea = that._getVisibleArea();
const position = label.getLayoutOptions().position;
let width = box.width;
let rowCountChanged = false;
if ("columns" === position && that.series.index > 0) {
width = visibleArea.maxX - that.centerX - that.radiusLabels
} else if ("inside" === position) {
if (width > visibleArea.maxX - visibleArea.minX) {
width = visibleArea.maxX - visibleArea.minX
}
} else if (moveLabelsFromCenter && box.x < that.centerX && box.width + box.x > that.centerX) {
width = Math.floor((visibleArea.maxX - visibleArea.minX) / 2)
} else if (box.x + width > visibleArea.maxX) {
width = visibleArea.maxX - box.x
} else if (box.x < visibleArea.minX) {
width = box.x + width - visibleArea.minX
}
if (width < box.width) {
rowCountChanged = label.fit(width)
}
return rowCountChanged
},
setLabelTrackerData: function() {
this._label.setTrackerData(this)
},
_checkLabelPosition: function(coord, bBox, visibleArea) {
coord = this._checkHorizontalLabelPosition(coord, bBox, visibleArea);
return this._checkVerticalLabelPosition(coord, bBox, visibleArea)
},
_getLabelConnector: function() {
const rad = this.radiusOuter;
const seriesStyle = this._options.styles.normal;
const strokeWidthBy2 = seriesStyle["stroke-width"] / 2;
const borderWidth = this.series.getOptions().containerBackgroundColor === seriesStyle.stroke ? _round(strokeWidthBy2) : _round(-strokeWidthBy2);
const angleFunctions = (0, _utils.getCosAndSin)(_round(this.middleAngle));
return {
x: _round(this.centerX + (rad - borderWidth) * angleFunctions.cos),
y: _round(this.centerY - (rad - borderWidth) * angleFunctions.sin),
angle: this.middleAngle
}
},
_drawMarker: function(renderer, group, animationEnabled, firstDrawing) {
const that = this;
let radiusOuter = that.radiusOuter;
let radiusInner = that.radiusInner;
let fromAngle = that.fromAngle;
let toAngle = that.toAngle;
if (animationEnabled) {
radiusInner = radiusOuter = 0;
if (!firstDrawing) {
fromAngle = toAngle = that.shiftedAngle
}
}
that.graphic = renderer.arc(that.centerX, that.centerY, radiusInner, radiusOuter, toAngle, fromAngle).attr({
"stroke-linejoin": "round"
}).smartAttr(that._getStyle()).data({
"chart-data-point": that
}).sharp().append(group)
},
getTooltipParams: function() {
const angleFunctions = (0, _utils.getCosAndSin)(this.middleAngle);
const radiusInner = this.radiusInner;
const radiusOuter = this.radiusOuter;
return {
x: this.centerX + (radiusInner + (radiusOuter - radiusInner) / 2) * angleFunctions.cos,
y: this.centerY - (radiusInner + (radiusOuter - radiusInner) / 2) * angleFunctions.sin,
offset: 0
}
},
_translate: function() {
const that = this;
const angle = that.shiftedAngle || 0;
const value = that.value;
const minValue = that.minValue;
const translator = that._getValTranslator();
that.fromAngle = translator.translate(minValue) + angle;
that.toAngle = translator.translate(value) + angle;
that.middleAngle = translator.translate((value - minValue) / 2 + minValue) + angle;
if (!that.isVisible()) {
that.middleAngle = that.toAngle = that.fromAngle = that.fromAngle || angle
}
},
getMarkerVisibility: function() {
return true
},
_updateMarker: function(animationEnabled, style, _, callback) {
const that = this;
if (!animationEnabled) {
style = _extend({
x: that.centerX,
y: that.centerY,
outerRadius: that.radiusOuter,
innerRadius: that.radiusInner,
startAngle: that.toAngle,
endAngle: that.fromAngle
}, style)
}
that.graphic.smartAttr(style).sharp();
callback && callback()
},
getLegendStyles: function() {
return this._styles.legendStyles
},
isInVisibleArea: function() {
return true
},
hide: function() {
const that = this;
if (that._visible) {
that._visible = false;
that.hideTooltip();
that._options.visibilityChanged()
}
},
show: function() {
const that = this;
if (!that._visible) {
that._visible = true;
that._options.visibilityChanged()
}
},
setInvisibility: function() {
this._label.draw(false)
},
isVisible: function() {
return this._visible
},
_getFormatObject: function(tooltip) {
const formatObject = _symbol_point.default._getFormatObject.call(this, tooltip);
const percent = this.percent;
formatObject.percent = percent;
formatObject.percentText = tooltip.formatValue(percent, "percent");
return formatObject
},
getColor: function() {
return this._styles.normal.fill
},
coordsIn: function(x, y) {
const lx = x - this.centerX;
const ly = y - this.centerY;
const r = _sqrt(lx * lx + ly * ly);
const fromAngle = this.fromAngle % 360;
const toAngle = this.toAngle % 360;
let angle;
if (r < this.radiusInner || r > this.radiusOuter || 0 === r) {
return false
}
angle = _acos(lx / r) * DEG * (ly > 0 ? -1 : 1);
if (angle < 0) {
angle += 360
}
if (fromAngle === toAngle && _abs(this.toAngle - this.fromAngle) > 1e-4) {
return true
} else {
return fromAngle >= toAngle ? angle <= fromAngle && angle >= toAngle : !(angle >= fromAngle && angle <= toAngle)
}
}
});
module.exports = exports.default;
module.exports.default = exports.default;