@amcharts/amcharts5
Version:
amCharts 5
420 lines (356 loc) • 13.4 kB
text/typescript
import * as am5 from "@amcharts/amcharts5";
import * as am5xy from "@amcharts/amcharts5/xy";
import * as am5stock from "@amcharts/amcharts5/stock";
import am5themes_Animated from "@amcharts/amcharts5/themes/Animated";
import "./data/AAPL_day.js";
import "./data/AMD_day.js";
import "./data/AMZN_day.js";
import "./data/GOOG_day.js";
import "./data/MSFT_day.js";
import "./data/NFLX_day.js";
import "./data/NVDA_day.js";
import "./data/TSLA_day.js";
// Create root element
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/getting-started/#Root_element
let root = am5.Root.new("chartdiv");
// Set themes
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/concepts/themes/
root.setThemes([
am5themes_Animated.new(root)
]);
// Create a stock chart
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/stock-chart/#Instantiating_the_chart
let stockChart = root.container.children.push(am5stock.StockChart.new(root, {
}));
// Set global number format
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/concepts/formatters/formatting-numbers/
root.numberFormatter.set("numberFormat", "#,###.00");
// Create a main stock panel (chart)
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/stock-chart/#Adding_panels
let mainPanel = stockChart.panels.push(am5stock.StockPanel.new(root, {
wheelY: "zoomX",
panX: true,
panY: true
}));
// Create value axis
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/xy-chart/axes/
let valueAxis = mainPanel.yAxes.push(am5xy.ValueAxis.new(root, {
renderer: am5xy.AxisRendererY.new(root, {
pan: "zoom"
}),
extraMin: 0.1, // adds some space for for main series
tooltip: am5.Tooltip.new(root, {}),
numberFormat: "#,###.00",
extraTooltipPrecision: 2
}));
let dateAxis = mainPanel.xAxes.push(am5xy.GaplessDateAxis.new(root, {
baseInterval: {
timeUnit: "day",
count: 1
},
renderer: am5xy.AxisRendererX.new(root, {
minorGridEnabled: true
}),
tooltip: am5.Tooltip.new(root, {})
}));
// Add series
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/xy-chart/series/
let valueSeries = mainPanel.series.push(am5xy.CandlestickSeries.new(root, {
name: "MSFT",
turboMode: true,
clustered: false,
valueXField: "Date",
valueYField: "Close",
highValueYField: "High",
lowValueYField: "Low",
openValueYField: "Open",
calculateAggregates: true,
xAxis: dateAxis,
yAxis: valueAxis,
legendValueText: "open: [bold]{openValueY}[/] high: [bold]{highValueY}[/] low: [bold]{lowValueY}[/] close: [bold]{valueY}[/]",
legendRangeValueText: ""
}));
// Set main value series
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/stock-chart/#Setting_main_series
stockChart.set("stockSeries", valueSeries);
// Add a stock legend
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/stock-chart/stock-legend/
let valueLegend = mainPanel.plotContainer.children.push(am5stock.StockLegend.new(root, {
stockChart: stockChart
}));
// Create volume axis
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/xy-chart/axes/
let volumeAxisRenderer = am5xy.AxisRendererY.new(root, {
inside: true
});
volumeAxisRenderer.labels.template.set("forceHidden", true);
volumeAxisRenderer.grid.template.set("forceHidden", true);
let volumeValueAxis = mainPanel.yAxes.push(am5xy.ValueAxis.new(root, {
numberFormat: "#.#a",
height: am5.percent(20),
y: am5.percent(100),
centerY: am5.percent(100),
renderer: volumeAxisRenderer
}));
// Add series
// https://www.amcharts.com/docs/v5/charts/xy-chart/series/
let volumeSeries = mainPanel.series.push(am5xy.ColumnSeries.new(root, {
name: "Volume",
turboMode: true,
clustered: false,
valueXField: "Date",
valueYField: "Volume",
xAxis: dateAxis,
yAxis: volumeValueAxis,
legendValueText: "[bold]{valueY.formatNumber('#,###.0a')}[/]"
}));
volumeSeries.columns.template.setAll({
strokeOpacity: 0,
fillOpacity: 0.5
});
// color columns by stock rules
volumeSeries.columns.template.adapters.add("fill", function(fill, target) {
let dataItem = target.dataItem;
if (dataItem) {
return stockChart.getVolumeColor(dataItem);
}
return fill;
})
// Set main series
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/stock-chart/#Setting_main_series
stockChart.set("volumeSeries", volumeSeries);
valueLegend.data.setAll([valueSeries, volumeSeries]);
// Add cursor(s)
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/xy-chart/cursor/
mainPanel.set("cursor", am5xy.XYCursor.new(root, {
yAxis: valueAxis,
xAxis: dateAxis,
snapToSeries: [valueSeries],
snapToSeriesBy: "y!"
}));
// Add scrollbar
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/xy-chart/scrollbars/
let scrollbar = mainPanel.set("scrollbarX", am5xy.XYChartScrollbar.new(root, {
orientation: "horizontal",
height: 50
}));
stockChart.toolsContainer.children.push(scrollbar);
let sbDateAxis = scrollbar.chart.xAxes.push(am5xy.GaplessDateAxis.new(root, {
baseInterval: {
timeUnit: "day",
count: 1
},
renderer: am5xy.AxisRendererX.new(root, {})
}));
let sbValueAxis = scrollbar.chart.yAxes.push(am5xy.ValueAxis.new(root, {
renderer: am5xy.AxisRendererY.new(root, {})
}));
let sbSeries = scrollbar.chart.series.push(am5xy.LineSeries.new(root, {
valueYField: "Close",
valueXField: "Date",
xAxis: sbDateAxis,
yAxis: sbValueAxis
}));
sbSeries.fills.template.setAll({
visible: true,
fillOpacity: 0.3
});
// Function that dynamically loads data
function loadData(ticker: string, series: am5xy.XYSeries[], granularity: string) {
let data = (<any>window)[ticker + "_" + granularity];
am5.array.each(series, function(item) {
item.data.setAll(data);
});
}
// Load initial data for the first series
let currentGranularity = "day";
loadData("MSFT", [valueSeries, volumeSeries, sbSeries], currentGranularity);
// Add comparing series
addComparingSeries("AAPL");
// Set up main indices selector
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/stock/toolbar/comparison-control/
var mainSeriesControl = am5stock.DropdownListControl.new(root, {
stockChart: stockChart,
name: valueSeries.get("name"),
icon: am5stock.StockIcons.getIcon("Search"),
fixedLabel: true,
searchable: true,
searchCallback: function(query) {
var mainSeries = stockChart.get("stockSeries");
var mainSeriesID = mainSeries ? mainSeries.get("name") : "";
var list = getTicker(query);
am5.array.each(list, function(item) {
if (item.id == mainSeriesID) {
item.disabled = true;
}
})
return list;
}
});
mainSeriesControl.events.on("selected", function(ev) {
var valueSeries = stockChart.get("stockSeries");
var volumeSeries = stockChart.get("volumeSeries");
mainSeriesControl.set("name", ev.item.subLabel);
valueSeries.set("name", ev.item.subLabel);
loadData(ev.item.subLabel, [valueSeries, volumeSeries, sbSeries], currentGranularity);
});
// Set up comparison control
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/stock/toolbar/comparison-control/
let comparisonControl = am5stock.ComparisonControl.new(root, {
stockChart: stockChart,
searchable: true,
searchCallback: (query) => {
var compared = stockChart.getPrivate("comparedSeries", []);
var main = stockChart.get("stockSeries");
if (compared.length > 4) {
return [{
label: "A maximum of 5 comparisons is already selected. Remove some to add new ones.",
id: "count",
info: true
}];
};
var comparedIds = [];
am5.array.each(compared, function(series) {
comparedIds.push(series.get("name"));
});
var list = getTicker(query);
am5.array.each(list, function(item) {
if (comparedIds.indexOf(item.id) !== -1 || main.get("name") == item.id) {
item.disabled = true;
}
})
return list;
}
});
comparisonControl.events.on("selected", function(ev) {
addComparingSeries(ev.item.subLabel);
});
function addComparingSeries(label) {
let series = am5xy.LineSeries.new(root, {
name: label,
valueYField: "Close",
calculateAggregates: true,
valueXField: "Date",
xAxis: dateAxis,
yAxis: valueAxis,
legendValueText: "{valueY.formatNumber('#.00')}"
});
let comparingSeries = stockChart.addComparingSeries(series);
loadData(label, [comparingSeries], currentGranularity);
}
function getTicker(search: string) {
search = search.toLowerCase();
let tickers = [
{ label: "Apple", subLabel: "AAPL", id: "AAPL" },
{ label: "Advanced Micro Devices", subLabel: "AMD", id: "AMD" },
{ label: "Microsoft", subLabel: "MSFT", id: "MSFT" },
{ label: "Alphabet (Google)", subLabel: "GOOG", id: "GOOG" },
{ label: "Amazon", subLabel: "AMZN", id: "AMZN" },
{ label: "Tesla", subLabel: "TSLA", id: "TSLA" },
{ label: "NVIDIA", subLabel: "NVDA", id: "NVDA" },
{ label: "Netflix", subLabel: "NFLX", id: "NFLX" }
];
return tickers.filter((item) => {
return item.label.toLowerCase().match(search) || item.subLabel.toLowerCase().match(search);
});
}
// Set up series type switcher
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/stock/toolbar/series-type-control/
let seriesSwitcher = am5stock.SeriesTypeControl.new(root, {
stockChart: stockChart
});
seriesSwitcher.events.on("selected", function(ev) {
setSeriesType(ev.item.id);
});
function getNewSettings(series: am5xy.XYSeries) {
let newSettings: any = [];
am5.array.each(["name", "valueYField", "highValueYField", "lowValueYField", "openValueYField", "calculateAggregates", "valueXField", "xAxis", "yAxis", "legendValueText", "legendRangeValueText", "stroke", "fill"], function(setting: any) {
newSettings[setting] = series.get(setting);
});
return newSettings;
}
function setSeriesType(seriesType: string) {
// Get current series and its settings
let currentSeries = stockChart.get("stockSeries")!;
let newSettings = getNewSettings(currentSeries);
// Remove previous series
let data = currentSeries.data.values;
mainPanel.series.removeValue(currentSeries);
// Create new series
let series;
switch (seriesType) {
case "line":
series = mainPanel.series.push(am5xy.LineSeries.new(root, newSettings));
break;
case "candlestick":
case "procandlestick":
newSettings.clustered = false;
series = mainPanel.series.push(am5xy.CandlestickSeries.new(root, newSettings));
if (seriesType == "procandlestick") {
series.columns.template.get("themeTags")!.push("pro");
}
break;
case "ohlc":
newSettings.clustered = false;
series = mainPanel.series.push(am5xy.OHLCSeries.new(root, newSettings));
break;
}
// Set new series as stockSeries
if (series) {
valueLegend.data.removeValue(currentSeries);
series.data.setAll(data);
stockChart.set("stockSeries", series);
let cursor = mainPanel.get("cursor");
if (cursor) {
cursor.set("snapToSeries", [series]);
}
valueLegend.data.insertIndex(0, series);
}
}
// Stock toolbar
// -------------------------------------------------------------------------------
// https://www.amcharts.com/docs/v5/charts/stock/toolbar/
let toolbar = am5stock.StockToolbar.new(root, {
container: document.getElementById("chartcontrols")!,
stockChart: stockChart,
controls: [
mainSeriesControl,
comparisonControl,
am5stock.IndicatorControl.new(root, {
stockChart: stockChart,
legend: valueLegend
}),
am5stock.DateRangeSelector.new(root, {
stockChart: stockChart
}),
am5stock.PeriodSelector.new(root, {
stockChart: stockChart
}),
seriesSwitcher,
am5stock.DrawingControl.new(root, {
stockChart: stockChart
}),
am5stock.ResetControl.new(root, {
stockChart: stockChart
}),
am5stock.SettingsControl.new(root, {
stockChart: stockChart
})
]
})