ag-charts-community
Version:
Advanced Charting / Charts supporting Javascript / Typescript / React / Angular / Vue
638 lines • 27.6 kB
JavaScript
"use strict";
var __extends = (this && this.__extends) || (function () {
var extendStatics = function (d, b) {
extendStatics = Object.setPrototypeOf ||
({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
return extendStatics(d, b);
};
return function (d, b) {
extendStatics(d, b);
function __() { this.constructor = d; }
d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
};
})();
var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
return c > 3 && r && Object.defineProperty(target, key, r), r;
};
var __read = (this && this.__read) || function (o, n) {
var m = typeof Symbol === "function" && o[Symbol.iterator];
if (!m) return o;
var i = m.call(o), r, ar = [], e;
try {
while ((n === void 0 || n-- > 0) && !(r = i.next()).done) ar.push(r.value);
}
catch (error) { e = { error: error }; }
finally {
try {
if (r && !r.done && (m = i["return"])) m.call(i);
}
finally { if (e) throw e.error; }
}
return ar;
};
var __spread = (this && this.__spread) || function () {
for (var ar = [], i = 0; i < arguments.length; i++) ar = ar.concat(__read(arguments[i]));
return ar;
};
Object.defineProperty(exports, "__esModule", { value: true });
var group_1 = require("../../../scene/group");
var line_1 = require("../../../scene/shape/line");
var text_1 = require("../../../scene/shape/text");
var selection_1 = require("../../../scene/selection");
var linearScale_1 = require("../../../scale/linearScale");
var sector_1 = require("../../../scene/shape/sector");
var series_1 = require("./../series");
var label_1 = require("../../label");
var node_1 = require("../../../scene/node");
var angle_1 = require("../../../util/angle");
var number_1 = require("../../../util/number");
var caption_1 = require("../../../caption");
var observable_1 = require("../../../util/observable");
var polarSeries_1 = require("./polarSeries");
var chartAxis_1 = require("../../chartAxis");
var chart_1 = require("../../chart");
var PieHighlightStyle = /** @class */ (function (_super) {
__extends(PieHighlightStyle, _super);
function PieHighlightStyle() {
return _super !== null && _super.apply(this, arguments) || this;
}
return PieHighlightStyle;
}(series_1.HighlightStyle));
var PieNodeTag;
(function (PieNodeTag) {
PieNodeTag[PieNodeTag["Sector"] = 0] = "Sector";
PieNodeTag[PieNodeTag["Callout"] = 1] = "Callout";
PieNodeTag[PieNodeTag["Label"] = 2] = "Label";
})(PieNodeTag || (PieNodeTag = {}));
var PieSeriesLabel = /** @class */ (function (_super) {
__extends(PieSeriesLabel, _super);
function PieSeriesLabel() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.offset = 3; // from the callout line
_this.minAngle = 20; // in degrees
return _this;
}
__decorate([
observable_1.reactive('change')
], PieSeriesLabel.prototype, "offset", void 0);
__decorate([
observable_1.reactive('dataChange')
], PieSeriesLabel.prototype, "minAngle", void 0);
__decorate([
observable_1.reactive('dataChange')
], PieSeriesLabel.prototype, "formatter", void 0);
return PieSeriesLabel;
}(label_1.Label));
var PieSeriesCallout = /** @class */ (function (_super) {
__extends(PieSeriesCallout, _super);
function PieSeriesCallout() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.colors = [
'#874349',
'#718661',
'#a48f5f',
'#5a7088',
'#7f637a',
'#5d8692'
];
_this.length = 10;
_this.strokeWidth = 1;
return _this;
}
__decorate([
observable_1.reactive('change')
], PieSeriesCallout.prototype, "colors", void 0);
__decorate([
observable_1.reactive('change')
], PieSeriesCallout.prototype, "length", void 0);
__decorate([
observable_1.reactive('change')
], PieSeriesCallout.prototype, "strokeWidth", void 0);
return PieSeriesCallout;
}(observable_1.Observable));
var PieSeriesTooltip = /** @class */ (function (_super) {
__extends(PieSeriesTooltip, _super);
function PieSeriesTooltip() {
return _super !== null && _super.apply(this, arguments) || this;
}
__decorate([
observable_1.reactive('change')
], PieSeriesTooltip.prototype, "renderer", void 0);
return PieSeriesTooltip;
}(series_1.SeriesTooltip));
exports.PieSeriesTooltip = PieSeriesTooltip;
var PieTitle = /** @class */ (function (_super) {
__extends(PieTitle, _super);
function PieTitle() {
var _this = _super !== null && _super.apply(this, arguments) || this;
_this.showInLegend = false;
return _this;
}
__decorate([
observable_1.reactive()
], PieTitle.prototype, "showInLegend", void 0);
return PieTitle;
}(caption_1.Caption));
exports.PieTitle = PieTitle;
var PieSeries = /** @class */ (function (_super) {
__extends(PieSeries, _super);
function PieSeries() {
var _this = _super.call(this) || this;
_this.radiusScale = new linearScale_1.LinearScale();
_this.groupSelection = selection_1.Selection.select(_this.pickGroup).selectAll();
/**
* The processed data that gets visualized.
*/
_this.groupSelectionData = [];
_this.angleScale = (function () {
var scale = new linearScale_1.LinearScale();
// Each slice is a ratio of the whole, where all ratios add up to 1.
scale.domain = [0, 1];
// Add 90 deg to start the first pie at 12 o'clock.
scale.range = [-Math.PI, Math.PI].map(function (angle) { return angle + Math.PI / 2; });
return scale;
})();
// When a user toggles a series item (e.g. from the legend), its boolean state is recorded here.
_this.seriesItemEnabled = [];
_this.label = new PieSeriesLabel();
_this.callout = new PieSeriesCallout();
_this.tooltip = new PieSeriesTooltip();
/**
* The key of the numeric field to use to determine the angle (for example,
* a pie slice angle).
*/
_this.angleKey = '';
_this.angleName = '';
_this._fills = [
'#c16068',
'#a2bf8a',
'#ebcc87',
'#80a0c3',
'#b58dae',
'#85c0d1'
];
_this._strokes = [
'#874349',
'#718661',
'#a48f5f',
'#5a7088',
'#7f637a',
'#5d8692'
];
_this.fillOpacity = 1;
_this.strokeOpacity = 1;
_this.lineDash = [0];
_this.lineDashOffset = 0;
/**
* The series rotation in degrees.
*/
_this.rotation = 0;
_this.outerRadiusOffset = 0;
_this.innerRadiusOffset = 0;
_this.strokeWidth = 1;
_this.highlightStyle = new PieHighlightStyle();
_this.addEventListener('update', _this.scheduleUpdate, _this);
_this.label.addEventListener('change', _this.scheduleUpdate, _this);
_this.label.addEventListener('dataChange', _this.scheduleData, _this);
_this.callout.addEventListener('change', _this.scheduleLayout, _this);
_this.addPropertyListener('data', function (event) {
if (event.value) {
event.source.seriesItemEnabled = event.value.map(function () { return true; });
}
});
return _this;
}
Object.defineProperty(PieSeries.prototype, "title", {
get: function () {
return this._title;
},
set: function (value) {
var oldTitle = this._title;
function updateLegend() {
this.fireEvent({ type: 'legendChange' });
}
if (oldTitle !== value) {
if (oldTitle) {
oldTitle.removeEventListener('change', this.scheduleUpdate, this);
oldTitle.addPropertyListener('showInLegend', updateLegend, this);
this.group.removeChild(oldTitle.node);
}
if (value) {
value.node.textBaseline = 'bottom';
value.addEventListener('change', this.scheduleUpdate, this);
value.addPropertyListener('showInLegend', updateLegend, this);
this.group.appendChild(value.node);
}
this._title = value;
this.scheduleUpdate();
}
},
enumerable: true,
configurable: true
});
Object.defineProperty(PieSeries.prototype, "fills", {
get: function () {
return this._fills;
},
set: function (values) {
this._fills = values;
this.scheduleUpdate();
},
enumerable: true,
configurable: true
});
Object.defineProperty(PieSeries.prototype, "strokes", {
get: function () {
return this._strokes;
},
set: function (values) {
this._strokes = values;
this.scheduleUpdate();
},
enumerable: true,
configurable: true
});
PieSeries.prototype.onHighlightChange = function () {
this.updateNodes();
};
PieSeries.prototype.setColors = function (fills, strokes) {
this.fills = fills;
this.strokes = strokes;
this.callout.colors = strokes;
};
PieSeries.prototype.getDomain = function (direction) {
if (direction === chartAxis_1.ChartAxisDirection.X) {
return this.angleScale.domain;
}
else {
return this.radiusScale.domain;
}
};
PieSeries.prototype.processData = function () {
var _this = this;
var _a = this, angleKey = _a.angleKey, radiusKey = _a.radiusKey, seriesItemEnabled = _a.seriesItemEnabled, angleScale = _a.angleScale, groupSelectionData = _a.groupSelectionData, label = _a.label;
var data = angleKey && this.data ? this.data : [];
var angleData = data.map(function (datum, index) { return seriesItemEnabled[index] && Math.abs(+datum[angleKey]) || 0; });
var angleDataTotal = angleData.reduce(function (a, b) { return a + b; }, 0);
// The ratios (in [0, 1] interval) used to calculate the end angle value for every pie slice.
// Each slice starts where the previous one ends, so we only keep the ratios for end angles.
var angleDataRatios = (function () {
var sum = 0;
return angleData.map(function (datum) { return sum += datum / angleDataTotal; });
})();
var labelFormatter = label.formatter;
var labelKey = label.enabled && this.labelKey;
var labelData = [];
var radiusData = [];
if (labelKey) {
if (labelFormatter) {
labelData = data.map(function (datum) { return labelFormatter({ value: datum[labelKey] }); });
}
else {
labelData = data.map(function (datum) { return String(datum[labelKey]); });
}
}
if (radiusKey) {
var _b = this, radiusMin = _b.radiusMin, radiusMax = _b.radiusMax;
var radii = data.map(function (datum) { return Math.abs(datum[radiusKey]); });
var min_1 = radiusMin !== undefined ? radiusMin : Math.min.apply(Math, __spread(radii));
var max = radiusMax !== undefined ? radiusMax : Math.max.apply(Math, __spread(radii));
var delta_1 = max - min_1;
radiusData = radii.map(function (value) { return delta_1 ? (value - min_1) / delta_1 : 1; });
}
groupSelectionData.length = 0;
var rotation = angle_1.toRadians(this.rotation);
var halfPi = Math.PI / 2;
var datumIndex = 0;
// Simply use reduce here to pair up adjacent ratios.
angleDataRatios.reduce(function (start, end) {
var radius = radiusKey ? radiusData[datumIndex] : 1;
var startAngle = angleScale.convert(start) + rotation;
var endAngle = angleScale.convert(end) + rotation;
var midAngle = (startAngle + endAngle) / 2;
var span = Math.abs(endAngle - startAngle);
var midCos = Math.cos(midAngle);
var midSin = Math.sin(midAngle);
var labelMinAngle = angle_1.toRadians(label.minAngle);
var labelVisible = labelKey && span > labelMinAngle;
var midAngle180 = angle_1.normalizeAngle180(midAngle);
// Split the circle into quadrants like so: ⊗
var quadrantStart = -3 * Math.PI / 4; // same as `normalizeAngle180(toRadians(-135))`
var textAlign;
var textBaseline;
if (midAngle180 >= quadrantStart && midAngle180 < (quadrantStart += halfPi)) {
textAlign = 'center';
textBaseline = 'bottom';
}
else if (midAngle180 >= quadrantStart && midAngle180 < (quadrantStart += halfPi)) {
textAlign = 'left';
textBaseline = 'middle';
}
else if (midAngle180 >= quadrantStart && midAngle180 < (quadrantStart += halfPi)) {
textAlign = 'center';
textBaseline = 'hanging';
}
else {
textAlign = 'right';
textBaseline = 'middle';
}
groupSelectionData.push({
series: _this,
datum: data[datumIndex],
itemId: datumIndex,
index: datumIndex,
radius: radius,
startAngle: startAngle,
endAngle: endAngle,
midAngle: midAngle,
midCos: midCos,
midSin: midSin,
label: labelVisible ? {
text: labelData[datumIndex],
textAlign: textAlign,
textBaseline: textBaseline
} : undefined
});
datumIndex++;
return end;
}, 0);
return true;
};
PieSeries.prototype.update = function () {
this.updatePending = false;
var _a = this, radius = _a.radius, innerRadiusOffset = _a.innerRadiusOffset, outerRadiusOffset = _a.outerRadiusOffset, title = _a.title;
this.radiusScale.range = [
innerRadiusOffset ? radius + innerRadiusOffset : 0,
radius + (outerRadiusOffset || 0)
];
this.group.translationX = this.centerX;
this.group.translationY = this.centerY;
if (title) {
var outerRadius = Math.max(0, this.radiusScale.range[1]);
if (outerRadius === 0) {
title.node.visible = false;
}
else {
title.node.translationY = -radius - outerRadiusOffset - 2;
title.node.visible = title.enabled;
}
}
this.updateSelections();
this.updateNodes();
};
PieSeries.prototype.updateSelections = function () {
if (!this.nodeDataPending) {
return;
}
this.nodeDataPending = false;
this.updateGroupSelection();
};
PieSeries.prototype.updateGroupSelection = function () {
var updateGroups = this.groupSelection.setData(this.groupSelectionData);
updateGroups.exit.remove();
var enterGroups = updateGroups.enter.append(group_1.Group);
enterGroups.append(sector_1.Sector).each(function (node) { return node.tag = PieNodeTag.Sector; });
enterGroups.append(line_1.Line).each(function (node) {
node.tag = PieNodeTag.Callout;
node.pointerEvents = node_1.PointerEvents.None;
});
enterGroups.append(text_1.Text).each(function (node) {
node.tag = PieNodeTag.Label;
node.pointerEvents = node_1.PointerEvents.None;
});
this.groupSelection = updateGroups.merge(enterGroups);
};
PieSeries.prototype.updateNodes = function () {
var _this = this;
if (!this.chart) {
return;
}
this.group.visible = this.visible && this.seriesItemEnabled.indexOf(true) >= 0;
var _a = this, fills = _a.fills, strokes = _a.strokes, fillOpacity = _a.fillOpacity, strokeOpacity = _a.strokeOpacity, radiusScale = _a.radiusScale, callout = _a.callout, shadow = _a.shadow, highlightedDatum = _a.chart.highlightedDatum, _b = _a.highlightStyle, deprecatedFill = _b.fill, deprecatedStroke = _b.stroke, deprecatedStrokeWidth = _b.strokeWidth, _c = _b.item, _d = _c.fill, highlightedFill = _d === void 0 ? deprecatedFill : _d, _e = _c.stroke, highlightedStroke = _e === void 0 ? deprecatedStroke : _e, _f = _c.strokeWidth, highlightedDatumStrokeWidth = _f === void 0 ? deprecatedStrokeWidth : _f, angleKey = _a.angleKey, radiusKey = _a.radiusKey, formatter = _a.formatter;
var centerOffsets = [];
var innerRadius = radiusScale.convert(0);
this.groupSelection.selectByTag(PieNodeTag.Sector).each(function (sector, datum, index) {
var radius = radiusScale.convert(datum.radius);
var isDatumHighlighted = !!highlightedDatum && highlightedDatum.series === _this && datum.itemId === highlightedDatum.itemId;
var fill = isDatumHighlighted && highlightedFill !== undefined ? highlightedFill : fills[index % fills.length];
var stroke = isDatumHighlighted && highlightedStroke !== undefined ? highlightedStroke : strokes[index % strokes.length];
var strokeWidth = isDatumHighlighted && highlightedDatumStrokeWidth !== undefined
? highlightedDatumStrokeWidth
: _this.getStrokeWidth(_this.strokeWidth);
var format = undefined;
if (formatter) {
format = formatter({
datum: datum.datum,
angleKey: angleKey,
radiusKey: radiusKey,
fill: fill,
stroke: stroke,
strokeWidth: strokeWidth,
highlighted: isDatumHighlighted
});
}
// Bring highlighted slice's parent group to front.
var parent = sector.parent && sector.parent.parent;
if (isDatumHighlighted && parent) {
parent.removeChild(sector.parent);
parent.appendChild(sector.parent);
}
sector.innerRadius = Math.max(0, innerRadius);
sector.outerRadius = Math.max(0, radius);
sector.startAngle = datum.startAngle;
sector.endAngle = datum.endAngle;
sector.fill = format && format.fill || fill;
sector.stroke = format && format.stroke || stroke;
sector.strokeWidth = format && format.strokeWidth !== undefined ? format.strokeWidth : strokeWidth;
sector.fillOpacity = fillOpacity;
sector.strokeOpacity = strokeOpacity;
sector.lineDash = _this.lineDash;
sector.lineDashOffset = _this.lineDashOffset;
sector.fillShadow = shadow;
sector.lineJoin = 'round';
sector.opacity = _this.getOpacity();
centerOffsets.push(sector.centerOffset);
});
var calloutColors = callout.colors, calloutLength = callout.length, calloutStrokeWidth = callout.strokeWidth;
this.groupSelection.selectByTag(PieNodeTag.Callout).each(function (line, datum, index) {
var radius = radiusScale.convert(datum.radius);
var outerRadius = Math.max(0, radius);
if (datum.label && outerRadius !== 0) {
line.strokeWidth = calloutStrokeWidth;
line.stroke = calloutColors[index % calloutColors.length];
line.x1 = datum.midCos * outerRadius;
line.y1 = datum.midSin * outerRadius;
line.x2 = datum.midCos * (outerRadius + calloutLength);
line.y2 = datum.midSin * (outerRadius + calloutLength);
}
else {
line.stroke = undefined;
}
});
{
var _g = this.label, offset_1 = _g.offset, fontStyle_1 = _g.fontStyle, fontWeight_1 = _g.fontWeight, fontSize_1 = _g.fontSize, fontFamily_1 = _g.fontFamily, color_1 = _g.color;
this.groupSelection.selectByTag(PieNodeTag.Label).each(function (text, datum, index) {
var label = datum.label;
var radius = radiusScale.convert(datum.radius);
var outerRadius = Math.max(0, radius);
if (label && outerRadius !== 0) {
var labelRadius = centerOffsets[index] + outerRadius + calloutLength + offset_1;
text.fontStyle = fontStyle_1;
text.fontWeight = fontWeight_1;
text.fontSize = fontSize_1;
text.fontFamily = fontFamily_1;
text.text = label.text;
text.x = datum.midCos * labelRadius;
text.y = datum.midSin * labelRadius;
text.fill = color_1;
text.textAlign = label.textAlign;
text.textBaseline = label.textBaseline;
}
else {
text.fill = undefined;
}
});
}
};
PieSeries.prototype.fireNodeClickEvent = function (event, datum) {
this.fireEvent({
type: 'nodeClick',
event: event,
series: this,
datum: datum.datum,
angleKey: this.angleKey,
labelKey: this.labelKey,
radiusKey: this.radiusKey
});
};
PieSeries.prototype.getTooltipHtml = function (nodeDatum) {
var angleKey = this.angleKey;
if (!angleKey) {
return '';
}
var _a = this, fills = _a.fills, tooltip = _a.tooltip, angleName = _a.angleName, radiusKey = _a.radiusKey, radiusName = _a.radiusName, labelKey = _a.labelKey, labelName = _a.labelName;
var tooltipRenderer = tooltip.renderer;
var color = fills[nodeDatum.index % fills.length];
var datum = nodeDatum.datum;
var label = labelKey ? datum[labelKey] + ": " : '';
var angleValue = datum[angleKey];
var formattedAngleValue = typeof angleValue === 'number' ? number_1.toFixed(angleValue) : angleValue.toString();
var title = this.title ? this.title.text : undefined;
var content = label + formattedAngleValue;
var defaults = {
title: title,
backgroundColor: color,
content: content
};
if (tooltipRenderer) {
return chart_1.toTooltipHtml(tooltipRenderer({
datum: datum,
angleKey: angleKey,
angleValue: angleValue,
angleName: angleName,
radiusKey: radiusKey,
radiusValue: radiusKey ? datum[radiusKey] : undefined,
radiusName: radiusName,
labelKey: labelKey,
labelName: labelName,
title: title,
color: color,
}), defaults);
}
return chart_1.toTooltipHtml(defaults);
};
PieSeries.prototype.listSeriesItems = function (legendData) {
var _this = this;
var _a = this, labelKey = _a.labelKey, data = _a.data;
if (data && data.length && labelKey) {
var _b = this, fills_1 = _b.fills, strokes_1 = _b.strokes, id_1 = _b.id;
var titleText_1 = this.title && this.title.showInLegend && this.title.text;
data.forEach(function (datum, index) {
var labelParts = [];
titleText_1 && labelParts.push(titleText_1);
labelParts.push(String(datum[labelKey]));
legendData.push({
id: id_1,
itemId: index,
enabled: _this.seriesItemEnabled[index],
label: {
text: labelParts.join(' - ')
},
marker: {
fill: fills_1[index % fills_1.length],
stroke: strokes_1[index % strokes_1.length],
fillOpacity: _this.fillOpacity,
strokeOpacity: _this.strokeOpacity
}
});
});
}
};
PieSeries.prototype.toggleSeriesItem = function (itemId, enabled) {
this.seriesItemEnabled[itemId] = enabled;
this.scheduleData();
};
PieSeries.className = 'PieSeries';
PieSeries.type = 'pie';
__decorate([
observable_1.reactive('dataChange')
], PieSeries.prototype, "angleKey", void 0);
__decorate([
observable_1.reactive('update')
], PieSeries.prototype, "angleName", void 0);
__decorate([
observable_1.reactive('dataChange')
], PieSeries.prototype, "radiusKey", void 0);
__decorate([
observable_1.reactive('update')
], PieSeries.prototype, "radiusName", void 0);
__decorate([
observable_1.reactive('dataChange')
], PieSeries.prototype, "radiusMin", void 0);
__decorate([
observable_1.reactive('dataChange')
], PieSeries.prototype, "radiusMax", void 0);
__decorate([
observable_1.reactive('dataChange')
], PieSeries.prototype, "labelKey", void 0);
__decorate([
observable_1.reactive('update')
], PieSeries.prototype, "labelName", void 0);
__decorate([
observable_1.reactive('layoutChange')
], PieSeries.prototype, "fillOpacity", void 0);
__decorate([
observable_1.reactive('layoutChange')
], PieSeries.prototype, "strokeOpacity", void 0);
__decorate([
observable_1.reactive('update')
], PieSeries.prototype, "lineDash", void 0);
__decorate([
observable_1.reactive('update')
], PieSeries.prototype, "lineDashOffset", void 0);
__decorate([
observable_1.reactive('update')
], PieSeries.prototype, "formatter", void 0);
__decorate([
observable_1.reactive('dataChange')
], PieSeries.prototype, "rotation", void 0);
__decorate([
observable_1.reactive('layoutChange')
], PieSeries.prototype, "outerRadiusOffset", void 0);
__decorate([
observable_1.reactive('dataChange')
], PieSeries.prototype, "innerRadiusOffset", void 0);
__decorate([
observable_1.reactive('layoutChange')
], PieSeries.prototype, "strokeWidth", void 0);
__decorate([
observable_1.reactive('layoutChange')
], PieSeries.prototype, "shadow", void 0);
return PieSeries;
}(polarSeries_1.PolarSeries));
exports.PieSeries = PieSeries;
//# sourceMappingURL=pieSeries.js.map