highcharts
Version:
JavaScript charting framework
280 lines (279 loc) • 10.4 kB
JavaScript
/* *
*
* (c) 2009-2025 Highsoft, Black Label
*
* License: www.highcharts.com/license
*
* !!!!!!! SOURCE GETS TRANSPILED BY TYPESCRIPT. EDIT TS FILE ONLY. !!!!!!!
*
* */
;
import U from '../../Core/Utilities.js';
const { addEvent, erase, find, fireEvent, pick, wrap } = U;
/* *
*
* Functions
*
* */
/**
* Add an annotation to the chart after render time.
*
* @sample highcharts/annotations/add-annotation/
* Add annotation
*
* @function Highcharts.Chart#addAnnotation
*
* @param {Highcharts.AnnotationsOptions} options
* The annotation options for the new, detailed annotation.
*
* @param {boolean} [redraw]
*
* @return {Highcharts.Annotation}
* The newly generated annotation.
*/
function chartAddAnnotation(userOptions, redraw) {
const annotation = this.initAnnotation(userOptions);
this.options.annotations.push(annotation.options);
if (pick(redraw, true)) {
annotation.redraw();
annotation.graphic.attr({
opacity: 1
});
}
return annotation;
}
/**
* @private
*/
function chartCallback() {
const chart = this;
chart.plotBoxClip = this.renderer.clipRect(this.plotBox);
chart.controlPointsGroup = chart.renderer
.g('control-points')
.attr({ zIndex: 99 })
.clip(chart.plotBoxClip)
.add();
chart.options.annotations.forEach((annotationOptions, i) => {
if (
// Verify that it has not been previously added in a responsive rule
!chart.annotations.some((annotation) => annotation.options === annotationOptions)) {
const annotation = chart.initAnnotation(annotationOptions);
chart.options.annotations[i] = annotation.options;
}
});
chart.drawAnnotations();
addEvent(chart, 'redraw', chart.drawAnnotations);
addEvent(chart, 'destroy', function () {
chart.plotBoxClip.destroy();
chart.controlPointsGroup.destroy();
});
addEvent(chart, 'exportData', function (event) {
const annotations = chart.annotations, csvColumnHeaderFormatter = ((this.options.exporting &&
this.options.exporting.csv) ||
{}).columnHeaderFormatter,
// If second row doesn't have xValues
// then it is a title row thus multiple level header is in use.
multiLevelHeaders = !event.dataRows[1].xValues, annotationHeader = (chart.options.lang &&
chart.options.lang.exportData &&
chart.options.lang.exportData.annotationHeader), columnHeaderFormatter = function (index) {
let s;
if (csvColumnHeaderFormatter) {
s = csvColumnHeaderFormatter(index);
if (s !== false) {
return s;
}
}
s = annotationHeader + ' ' + index;
if (multiLevelHeaders) {
return {
columnTitle: s,
topLevelColumnTitle: s
};
}
return s;
}, startRowLength = event.dataRows[0].length, annotationSeparator = (chart.options.exporting &&
chart.options.exporting.csv &&
chart.options.exporting.csv.annotations &&
chart.options.exporting.csv.annotations.itemDelimiter), joinAnnotations = (chart.options.exporting &&
chart.options.exporting.csv &&
chart.options.exporting.csv.annotations &&
chart.options.exporting.csv.annotations.join);
annotations.forEach((annotation) => {
if (annotation.options.labelOptions &&
annotation.options.labelOptions.includeInDataExport) {
annotation.labels.forEach((label) => {
if (label.options.text) {
const annotationText = label.options.text;
label.points.forEach((points) => {
const annotationX = points.x, xAxisIndex = points.series.xAxis ?
points.series.xAxis.index :
-1;
let wasAdded = false;
// Annotation not connected to any xAxis -
// add new row.
if (xAxisIndex === -1) {
const n = event.dataRows[0].length, newRow = new Array(n);
for (let i = 0; i < n; ++i) {
newRow[i] = '';
}
newRow.push(annotationText);
newRow.xValues = [];
newRow.xValues[xAxisIndex] = annotationX;
event.dataRows.push(newRow);
wasAdded = true;
}
// Annotation placed on a exported data point
// - add new column
if (!wasAdded) {
event.dataRows.forEach((row) => {
if (!wasAdded &&
row.xValues &&
xAxisIndex !== void 0 &&
annotationX === row.xValues[xAxisIndex]) {
if (joinAnnotations &&
row.length > startRowLength) {
row[row.length - 1] += (annotationSeparator +
annotationText);
}
else {
row.push(annotationText);
}
wasAdded = true;
}
});
}
// Annotation not placed on any exported data point,
// but connected to the xAxis - add new row
if (!wasAdded) {
const n = event.dataRows[0].length, newRow = new Array(n);
for (let i = 0; i < n; ++i) {
newRow[i] = '';
}
newRow[0] = annotationX;
newRow.push(annotationText);
newRow.xValues = [];
if (xAxisIndex !== void 0) {
newRow.xValues[xAxisIndex] = annotationX;
}
event.dataRows.push(newRow);
}
});
}
});
}
});
let maxRowLen = 0;
event.dataRows.forEach((row) => {
maxRowLen = Math.max(maxRowLen, row.length);
});
const newRows = maxRowLen - event.dataRows[0].length;
for (let i = 0; i < newRows; i++) {
const header = columnHeaderFormatter(i + 1);
if (multiLevelHeaders) {
event.dataRows[0].push(header.topLevelColumnTitle);
event.dataRows[1].push(header.columnTitle);
}
else {
event.dataRows[0].push(header);
}
}
});
}
/**
* @private
*/
function chartDrawAnnotations() {
this.plotBoxClip.attr(this.plotBox);
this.annotations.forEach((annotation) => {
annotation.redraw();
annotation.graphic.animate({
opacity: 1
}, annotation.animationConfig);
});
}
/**
* Remove an annotation from the chart.
*
* @function Highcharts.Chart#removeAnnotation
*
* @param {number|string|Highcharts.Annotation} idOrAnnotation
* The annotation's id or direct annotation object.
*/
function chartRemoveAnnotation(idOrAnnotation) {
const annotations = this.annotations, annotation = (idOrAnnotation.coll === 'annotations') ?
idOrAnnotation :
find(annotations, function (annotation) {
return annotation.options.id === idOrAnnotation;
});
if (annotation) {
fireEvent(annotation, 'remove');
erase(this.options.annotations, annotation.options);
erase(annotations, annotation);
annotation.destroy();
}
}
/**
* Create lookups initially
* @private
*/
function onChartAfterInit() {
const chart = this;
chart.annotations = [];
if (!this.options.annotations) {
this.options.annotations = [];
}
}
/**
* @private
*/
function wrapPointerOnContainerMouseDown(proceed) {
if (!this.chart.hasDraggedAnnotation) {
proceed.apply(this, Array.prototype.slice.call(arguments, 1));
}
}
/* *
*
* Composition
*
* */
/**
* @private
*/
var AnnotationChart;
(function (AnnotationChart) {
/* *
*
* Functions
*
* */
/**
* @private
*/
function compose(AnnotationClass, ChartClass, PointerClass) {
const chartProto = ChartClass.prototype;
if (!chartProto.addAnnotation) {
const pointerProto = PointerClass.prototype;
addEvent(ChartClass, 'afterInit', onChartAfterInit);
chartProto.addAnnotation = chartAddAnnotation;
chartProto.callbacks.push(chartCallback);
chartProto.collectionsWithInit.annotations = [chartAddAnnotation];
chartProto.collectionsWithUpdate.push('annotations');
chartProto.drawAnnotations = chartDrawAnnotations;
chartProto.removeAnnotation = chartRemoveAnnotation;
chartProto.initAnnotation = function chartInitAnnotation(userOptions) {
const Constructor = (AnnotationClass.types[userOptions.type] ||
AnnotationClass), annotation = new Constructor(this, userOptions);
this.annotations.push(annotation);
return annotation;
};
wrap(pointerProto, 'onContainerMouseDown', wrapPointerOnContainerMouseDown);
}
}
AnnotationChart.compose = compose;
})(AnnotationChart || (AnnotationChart = {}));
/* *
*
* Default Export
*
* */
export default AnnotationChart;