@syncfusion/ej2-charts
Version:
Feature-rich chart control with built-in support for over 25 chart types, technical indictors, trendline, zooming, tooltip, selection, crosshair and trackball.
300 lines (299 loc) • 17 kB
JavaScript
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 __());
};
})();
import { withIn, PointData, textElement, getElement, valueToCoefficient, drawSymbol, ChartLocation } from '../../common/utils/helper';
import { BaseTooltip } from '../../common/user-interaction/tooltip';
import { Tooltip, PathOption, TextOption, measureText, Size } from '@syncfusion/ej2-svg-base';
import { createElement, remove } from '@syncfusion/ej2-base';
import { DataUtil } from '@syncfusion/ej2-data';
import { stockEventRender } from '../../common/model/constants';
/**
* @private
*/
var StockEvents = /** @class */ (function (_super) {
__extends(StockEvents, _super);
function StockEvents(stockChart) {
var _this = _super.call(this, stockChart.chart) || this;
/** @private */
_this.symbolLocations = [];
_this.stockChart = stockChart;
_this.chartId = _this.stockChart.element.id;
return _this;
}
/**
* To render stock events in chart
*
* @returns {Element} Stock event element
* @private
*/
StockEvents.prototype.renderStockEvents = function () {
var sChart = this.stockChart;
var stockEvent;
var stockEventElement;
var textSize;
// Creation of group elements for stock events
var stockEventsElementGroup = sChart.renderer.createGroup({ id: this.chartId + '_StockEvents' });
this.symbolLocations = initialArray(sChart.series.length, sChart.stockEvents.length, new ChartLocation(0, 0));
for (var i = 0; i < sChart.stockEvents.length; i++) {
stockEvent = this.stockChart.stockEvents[i];
for (var _i = 0, _a = sChart.chart.series; _i < _a.length; _i++) {
var series = _a[_i];
var argsData = {
name: stockEventRender, stockChart: sChart, text: stockEvent.text,
type: stockEvent.type, cancel: false, series: series
};
sChart.trigger(stockEventRender, argsData);
stockEvent.text = argsData.text;
stockEvent.type = argsData.type;
textSize = measureText(stockEvent.text + 'W', stockEvent.textStyle, this.stockChart.themeStyle.axisLabelFont);
if (!argsData.cancel) {
stockEventElement = sChart.renderer.createGroup({ id: this.chartId + '_Series_' + series.index + '_StockEvents_' + i });
var stockEventDate = this.dateParse(stockEvent.date).getTime();
stockEventDate = this.stockChart.isDateTimeCategory ? series.xAxis.labels.indexOf(stockEventDate.toString()) :
stockEventDate;
if (withIn(stockEventDate, series.xAxis.visibleRange) && (stockEventDate >= series.xMin &&
stockEventDate <= series.xMax)) {
if (stockEvent.seriesIndexes.length > 0) {
for (var j = 0; j < stockEvent.seriesIndexes.length; j++) {
if (stockEvent.seriesIndexes[j] === series.index) {
stockEventsElementGroup.appendChild(this.creatEventGroup(stockEventElement, series, stockEvent, i, textSize));
}
}
}
else {
stockEventsElementGroup.appendChild(this.creatEventGroup(stockEventElement, series, stockEvent, i, textSize));
}
}
}
}
}
return stockEventsElementGroup;
};
StockEvents.prototype.creatEventGroup = function (stockEventElement, series, stockEvent, i, textSize) {
var symbolLocation = this.findClosePoint(series, stockEvent);
if (!stockEvent.showOnSeries) {
symbolLocation.y = series.yAxis.rect.y + series.yAxis.rect.height;
}
this.symbolLocations[series.index][i] = symbolLocation;
this.createStockElements(stockEventElement, stockEvent, series, i, symbolLocation, textSize);
return stockEventElement;
};
StockEvents.prototype.findClosePoint = function (series, sEvent) {
var stockEventDate = this.dateParse(sEvent.date).getTime();
stockEventDate = this.stockChart.isDateTimeCategory ? series.xAxis.labels.indexOf(stockEventDate.toString()) : stockEventDate;
var closeIndex = this.getClosest(series, stockEventDate);
var pointData;
var point;
var yPixel;
for (var k = 0; k < series.points.length; k++) {
point = series.points[k];
if (closeIndex === point.xValue && point.visible) {
pointData = new PointData(point, series);
}
else if (k !== 0 && k !== series.points.length - 1) {
if (closeIndex > series.points[k - 1].xValue && closeIndex < series.points[k + 1].xValue) {
pointData = new PointData(point, series);
}
}
}
var xPixel = series.xAxis.rect.x + valueToCoefficient(pointData.point.xValue, series.xAxis) * series.xAxis.rect.width;
yPixel = valueToCoefficient(pointData.point[sEvent.placeAt], series.yAxis) * series.yAxis.rect.height;
yPixel = (yPixel * -1) + (series.yAxis.rect.y + series.yAxis.rect.height);
return new ChartLocation(xPixel, yPixel);
};
StockEvents.prototype.createStockElements = function (stockEventElement, stockEve, series, i, symbolLocation, textSize) {
var result = new Size(textSize.width > 20 ? textSize.width : 20, textSize.height > 20 ? textSize.height : 20);
var pathString;
var pathOption;
var lx = symbolLocation.x;
var ly = symbolLocation.y;
var stockId = this.chartId + '_Series_' + series.index + '_StockEvents_' + i;
var border = stockEve.border;
switch (stockEve.type) {
case 'Flag':
case 'Circle':
case 'Square':
stockEventElement.appendChild(drawSymbol(new ChartLocation(lx, ly), 'Circle', new Size(2, 2), '', new PathOption(stockId + '_Circle', 'transparent', border.width, border.color), this.dateParse(stockEve.date).toISOString()));
stockEventElement.appendChild(drawSymbol(new ChartLocation(lx, ly - 5), 'VerticalLine', new Size(9, 9), '', new PathOption(stockId + '_Path', border.color, border.width, border.color), this.dateParse(stockEve.date).toISOString()));
stockEventElement.appendChild(drawSymbol(new ChartLocation(stockEve.type !== 'Flag' ? lx : lx + result.width / 2, ly - result.height), stockEve.type, result, '', new PathOption(stockId + '_Shape', stockEve.background, border.width, border.color), this.dateParse(stockEve.date).toISOString()));
textElement(this.stockChart.renderer, new TextOption(stockId + '_Text', stockEve.type !== 'Flag' ? symbolLocation.x : symbolLocation.x + result.width / 2, (symbolLocation.y - result.height), 'middle', stockEve.text, '', 'middle'), stockEve.textStyle, stockEve.textStyle.color, stockEventElement);
break;
case 'ArrowUp':
case 'ArrowDown':
case 'ArrowRight':
case 'ArrowLeft':
pathString = 'M' + ' ' + lx + ' ' + ly + ' ' + this.findArrowpaths(stockEve.type);
pathOption = new PathOption(stockId + '_Shape', stockEve.background, border.width, border.color, 1, '', pathString);
stockEventElement.appendChild(this.stockChart.renderer.drawPath(pathOption));
break;
case 'Triangle':
case 'InvertedTriangle':
result.height = 3 * textSize.height;
result.width = textSize.width + (1.5 * textSize.width);
stockEventElement.appendChild(drawSymbol(new ChartLocation(symbolLocation.x, symbolLocation.y), stockEve.type, new Size(20, 20), '', new PathOption(stockId + '_Shape', stockEve.background, border.width, border.color), this.dateParse(stockEve.date).toISOString()));
textElement(this.stockChart.renderer, new TextOption(stockId + '_Text', symbolLocation.x, symbolLocation.y, 'middle', stockEve.text, '', 'middle'), stockEve.textStyle, stockEve.textStyle.color, stockEventElement);
break;
case 'Text':
textSize.height += 8; //padding for text height
pathString = 'M' + ' ' + (lx) + ' ' + (ly) + ' ' +
'L' + ' ' + (lx - 5) + ' ' + (ly - 5) + ' ' +
'L' + ' ' + (lx - ((textSize.width) / 2)) + ' ' + (ly - 5) + ' ' +
'L' + ' ' + (lx - ((textSize.width) / 2)) + ' ' + (ly - textSize.height) + ' ' +
'L' + ' ' + (lx + ((textSize.width) / 2)) + ' ' + (ly - textSize.height) + ' ' +
'L' + ' ' + (lx + ((textSize.width) / 2)) + ' ' + (ly - 5) + ' ' +
'L' + ' ' + (lx + 5) + ' ' + (ly - 5) + ' ' + 'Z';
pathOption = new PathOption(stockId + '_Shape', stockEve.background, border.width, border.color, 1, '', pathString);
stockEventElement.appendChild(this.stockChart.renderer.drawPath(pathOption));
textElement(this.stockChart.renderer, new TextOption(stockId + '_Text', lx, ly - (textSize.height / 2), 'middle', stockEve.text, '', 'middle'), stockEve.textStyle, stockEve.textStyle.color, stockEventElement);
break;
default:
//pin type calculation.
pathString = 'M' + ' ' + lx + ' ' + ly + ' ' +
'L' + ' ' + (lx - ((textSize.width) / 2)) + ' ' + (ly - textSize.height / 3) + ' ' +
'L' + ' ' + (lx - ((textSize.width) / 2)) + ' ' + (ly - textSize.height) + ' ' +
'L' + ' ' + (lx + ((textSize.width) / 2)) + ' ' + (ly - textSize.height) + ' ' +
'L' + ' ' + (lx + ((textSize.width) / 2)) + ' ' + (ly - textSize.height / 3) + ' ' + 'Z';
pathOption = new PathOption(stockId + '_Shape', stockEve.background, border.width, border.color, 1, '', pathString);
stockEventElement.appendChild(this.stockChart.renderer.drawPath(pathOption));
//append text element
textElement(this.stockChart.renderer, new TextOption(stockId + '_Text', lx, ly - (textSize.height / 2), 'middle', stockEve.text, '', 'middle'), stockEve.textStyle, stockEve.textStyle.color, stockEventElement);
}
};
StockEvents.prototype.renderStockEventTooltip = function (targetId) {
var seriesIndex = parseInt((targetId.split('_StockEvents_')[0]).split(this.chartId + '_Series_')[1], 10);
var pointIndex = parseInt(targetId.split('_StockEvents_')[1].replace(/\D+/g, ''), 10);
var updatedLocation = this.symbolLocations[seriesIndex][pointIndex];
var pointLocation = new ChartLocation(updatedLocation.x, updatedLocation.y + this.stockChart.toolbarHeight + this.stockChart.titleSize.height);
this.applyHighLights(pointIndex, seriesIndex);
//title size and toolbar height is added location for placing tooltip
var svgElement = this.getElement(this.chartId + '_StockEvents_Tooltip_svg');
var isTooltip = (this.stockEventTooltip && svgElement && parseInt(svgElement.getAttribute('opacity'), 10) > 0);
if (!isTooltip) {
if (getElement(this.chartId + '_StockEvents_Tooltip_svg')) {
remove(getElement(this.chartId + '_StockEvents_Tooltip'));
}
var tooltipElement = createElement('div', {
id: this.chartId + '_StockEvents_Tooltip', className: 'ejSVGTooltip',
attrs: { 'style': 'pointer-events:none; position:absolute;z-index: 1' }
});
getElement(this.chartId + '_Secondary_Element').appendChild(tooltipElement);
this.stockEventTooltip = new Tooltip({
opacity: 1,
header: '', content: [(this.stockChart.stockEvents[pointIndex].description)],
enableAnimation: true, location: pointLocation,
theme: this.stockChart.theme,
inverted: true,
areaBounds: this.stockChart.chart.chartAxisLayoutPanel.seriesClipRect
});
this.stockEventTooltip.areaBounds.y += this.stockChart.toolbarHeight + this.stockChart.titleSize.height;
this.stockEventTooltip.appendTo('#' + tooltipElement.id);
}
else {
this.stockEventTooltip.content = [(this.stockChart.stockEvents[pointIndex].description)];
this.stockEventTooltip.location = pointLocation;
this.stockEventTooltip.dataBind();
}
};
/**
* Remove the stock event tooltip
*
* @param {number} duration tooltip timeout duration
* @returns {void}
*/
StockEvents.prototype.removeStockEventTooltip = function (duration) {
var _this = this;
var tooltipElement = this.getElement(this.chartId + '_StockEvents_Tooltip');
this.stopAnimation();
if (tooltipElement && this.stockEventTooltip) {
this.toolTipInterval = +setTimeout(function () {
_this.stockEventTooltip.fadeOut();
_this.removeHighLights();
}, duration);
}
else if (tooltipElement && this.stockChart.onPanning) {
remove(tooltipElement);
}
};
StockEvents.prototype.findArrowpaths = function (type) {
var arrowString = '';
switch (type) {
case 'ArrowUp':
arrowString = 'l -10 10 l 5 0 l 0 10 l 10 0 l 0 -10 l 5 0 z';
break;
case 'ArrowDown':
arrowString = 'l -10 -10 l 5 0 l 0 -10 l 10 0 l 0 10 l 5 0 z';
break;
case 'ArrowLeft':
arrowString = 'l -10 -10 l 0 5 l -10 0 l 0 10 l 10 0 l 0 5 z';
break;
case 'ArrowRight':
arrowString = 'l 10 -10 l 0 5 l 10 0 l 0 10 l -10 0 l 0 5 z';
break;
}
return arrowString;
};
StockEvents.prototype.applyHighLights = function (pointIndex, seriesIndex) {
if (this.pointIndex !== pointIndex || this.seriesIndex !== seriesIndex) {
this.removeHighLights();
}
this.pointIndex = pointIndex;
this.seriesIndex = seriesIndex;
var stockId = this.chartId + '_Series_' + seriesIndex + '_StockEvents_' + pointIndex;
this.setOpacity(stockId + '_Shape', 0.5);
this.setOpacity(stockId + '_Text', 0.5);
};
StockEvents.prototype.removeHighLights = function () {
var stockId = this.chartId + '_Series_' + this.seriesIndex + '_StockEvents_' + this.pointIndex;
this.setOpacity(stockId + '_Shape', 1);
this.setOpacity(stockId + '_Text', 1);
};
StockEvents.prototype.setOpacity = function (elementId, opacity) {
if (getElement(elementId)) {
getElement(elementId).setAttribute('opacity', opacity.toString());
}
};
/**
* To convert the c# or javascript date formats into js format
* refer chart control's dateTime processing.
*
* @param {Date | string} value date or string value
* @returns {Date} date format value
*/
StockEvents.prototype.dateParse = function (value) {
var dateParser = this.chart.intl.getDateParser({ skeleton: 'full', type: 'dateTime' });
var dateFormatter = this.chart.intl.getDateFormat({ skeleton: 'full', type: 'dateTime' });
return new Date((Date.parse(dateParser(dateFormatter(new Date(DataUtil.parse.parseJson({ val: value }).val))))));
};
return StockEvents;
}(BaseTooltip));
export { StockEvents };
/**
* To initial the array.
*
* @private
* @param {number} numrows The number of rows in the array.
* @param {number} numcols The number of columns in the array.
* @param {ChartLocation} initial The initial value to fill the array with.
* @returns {ChartLocation[]} An array filled with the specified initial value.
*/
function initialArray(numrows, numcols, initial) {
var arr = [];
for (var i = 0; i < numrows; ++i) {
var columns = [];
for (var j = 0; j < numcols; ++j) {
columns[j] = initial;
}
arr[i] = columns;
}
return arr;
}