Comparison control can be added to stock toolbar, and is used to interactively add additional series to the Stock chart, so that they can be compared to main series.
Adding
Like any other control, it should be instantiated using new()
syntax, and pushed into toolbar's controls
list:
// Add comparison control let comparisonControl = am5stock.ComparisonControl.new(root, { stockChart: stockChart, items: [] }); // Add toolbar let toolbar = am5stock.StockToolbar.new(root, { container: document.getElementById("chartcontrols"), stockChart: stockChart, controls: [ comparisonControl ] });
// Add comparison control var comparisonControl = am5stock.ComparisonControl.new(root, { stockChart: stockChart, items: [ ] }); // Add toolbar var toolbar = am5stock.StockToolbar.new(root, { container: document.getElementById("chartcontrols"), stockChart: stockChart, controls: [ comparisonControl ] });
This will add a control, but it won't be useful because it doesn't have any items to choose from, nor events to create compared series in.
List items
There are two ways to populate the list with: providing static item array and/or search callbacks.
Static item list
To provide a list of items to choose from, we can use control's items
setting.
It accepts an array of objects like this:
{ label: "Apple", subLabel: "AAPL", id: "AAPL" }
The label
and id
are required, whereas subLabel
is optional.
Let's try and add a couple of items:
// Add comparison control let comparisonControl = am5stock.ComparisonControl.new(root, { stockChart: stockChart, items: [ { label: "Apple", subLabel: "AAPL", id: "AAPL" }, { label: "Tesla", subLabel: "TSLA", id: "TSLA" }, ] }); // Add toolbar let toolbar = am5stock.StockToolbar.new(root, { container: document.getElementById("chartcontrols"), stockChart: stockChart, controls: [ comparisonControl ] });
// Add comparison control var comparisonControl = am5stock.ComparisonControl.new(root, { stockChart: stockChart, items: [ { label: "Apple", subLabel: "AAPL", id: "AAPL" }, { label: "Tesla", subLabel: "TSLA", id: "TSLA" } ] }); // Add toolbar var toolbar = am5stock.StockToolbar.new(root, { container: document.getElementById("chartcontrols"), stockChart: stockChart, controls: [ comparisonControl ] });
Now, when we click the control, we'll get two items to choose from:
Enabling search
If we would like out list to be searchable, we need to enable it by setting searchable: true
in control's settings:
// Add comparison control let comparisonControl = am5stock.ComparisonControl.new(root, { stockChart: stockChart, searchable: true, items: [ { label: "Apple", subLabel: "AAPL", id: "AAPL" }, { label: "Tesla", subLabel: "TSLA", id: "TSLA" }, ] }); // Add toolbar let toolbar = am5stock.StockToolbar.new(root, { container: document.getElementById("chartcontrols"), stockChart: stockChart, controls: [ comparisonControl ] });
// Add comparison control var comparisonControl = am5stock.ComparisonControl.new(root, { stockChart: stockChart, searchable: true, items: [ { label: "Apple", subLabel: "AAPL", id: "AAPL" }, { label: "Tesla", subLabel: "TSLA", id: "TSLA" } ] }); // Add toolbar var toolbar = am5stock.StockToolbar.new(root, { container: document.getElementById("chartcontrols"), stockChart: stockChart, controls: [ comparisonControl ] });
Dynamic search results
We can also hook up a custom function, that would provide dynamic item list based on what user is typing into the search box of the control.
For that we have a setting searchCallback
which should be set to a function that accepts query string as a parameter, and returns an item array or a Promise
.
// Add comparison control let comparisonControl = am5stock.ComparisonControl.new(root, { stockChart: stockChart, searchable: true, searchCallback: function(query) { // ... } }); // Add toolbar let toolbar = am5stock.StockToolbar.new(root, { container: document.getElementById("chartcontrols"), stockChart: stockChart, controls: [ comparisonControl ] });
// Add comparison control var comparisonControl = am5stock.ComparisonControl.new(root, { stockChart: stockChart, searchable: true, searchCallback: function(query) { // ... } }); // Add toolbar var toolbar = am5stock.StockToolbar.new(root, { container: document.getElementById("chartcontrols"), stockChart: stockChart, controls: [ comparisonControl ] });
The reason why the callback would return a Promise
is that it would allow search results to be loaded asynchronously, such as ones loaded via AJAX.
Adding series
After comparison item is selected, we need to actually create a series for it, configure and load data for it, then provide it to the chart using addComparingSeries()
method.
To catch the moment item is selected, we'll use comparison control's selected
event.
comparisonControl.events.on("selected", function(ev) { let item = ev.item; let series = am5xy.LineSeries.new(root, { name: item.subLabel, valueYField: "Close", calculateAggregates: true, valueXField: "Date", xAxis: dateAxis, yAxis: valueAxis, legendValueText: "{valueY.formatNumber('#.00')}" }); let comparingSeries = stockChart.addComparingSeries(series); comparingSeries.data.set(newData); });
comparisonControl.events.on("selected", function(ev) { var item = ev.item; var series = am5xy.LineSeries.new(root, { name: item.subLabel, valueYField: "Close", calculateAggregates: true, valueXField: "Date", xAxis: dateAxis, yAxis: valueAxis, legendValueText: "{valueY.formatNumber('#.00')}" }); var comparingSeries = stockChart.addComparingSeries(series); comparingSeries.data.set(newData); });
Asynchronous data
We can load data for the loaded series asynchronously, too.
comparisonControl.events.on("selected", function(ev) { let item = ev.item; let series = am5xy.LineSeries.new(root, { name: item.subLabel, valueYField: "Close", calculateAggregates: true, valueXField: "Date", xAxis: dateAxis, yAxis: valueAxis, legendValueText: "{valueY.formatNumber('#.00')}" }); let comparingSeries = stockChart.addComparingSeries(series); loadData(item.subLabel, [comparingSeries]); }); function loadData(ticker, series) { // Load external data // https://www.amcharts.com/docs/v5/charts/xy-chart/series/#Setting_data am5.net.load("https://mywebserver.com/data/" + ticker + ".csv").then(function(result) { // Parse loaded data let data = am5.CSVParser.parse(result.response, { delimiter: ",", skipEmpty: true, useColumnNames: true }); // Process data (convert dates and values) let processor = am5.DataProcessor.new(root, { dateFields: ["Date"], dateFormat: "yyyy-MM-dd", numericFields: ["Open", "High", "Low", "Close", "Adj Close", "Volume"] }); processor.processMany(data); // Set data am5.array.each(series, function(item) { item.data.setAll(data); }); }); }
comparisonControl.events.on("selected", function(ev) { var item = ev.item; var series = am5xy.LineSeries.new(root, { name: item.subLabel, valueYField: "Close", calculateAggregates: true, valueXField: "Date", xAxis: dateAxis, yAxis: valueAxis, legendValueText: "{valueY.formatNumber('#.00')}" }); var comparingSeries = stockChart.addComparingSeries(series); loadData(item.subLabel, [comparingSeries]); }); function loadData(ticker, series) { // Load external data // https://www.amcharts.com/docs/v5/charts/xy-chart/series/#Setting_data am5.net.load("https://mywebserver.com/data/" + ticker + ".csv").then(function(result) { // Parse loaded data var data = am5.CSVParser.parse(result.response, { delimiter: ",", skipEmpty: true, useColumnNames: true }); // Process data (convert dates and values) var processor = am5.DataProcessor.new(root, { dateFields: ["Date"], dateFormat: "yyyy-MM-dd", numericFields: ["Open", "High", "Low", "Close", "Adj Close", "Volume"] }); processor.processMany(data); // Set data am5.array.each(series, function(item) { item.data.setAll(data); }); }); }
NOTEThe above code is using amCharts 5 built-in net.load()
utility as well as data parser and processor to asynchronously load and parse data.
Percent scale
By default, adding a comparison series will switch the chart into a "percent mode".
For more information, check out "Percent mode" tutorial.
Examples
Static list
See the Pen Stock chart with comparison by amCharts team (@amcharts) on CodePen.
Dynamic list
See the Pen Stock chart with comparison by amCharts team (@amcharts) on CodePen.