Selecting and Marking Multiple Ranges
Click and drag on plot area to select a range on a chart. Chart creates an axis range in the place of a selection and also checks if a new range is not overlapping with previously created.
Key implementation details
We use cursor events here (selectstarted
and selectended
) to track selection start and end positions and then transform these positions to values using axis’ positionToValue()
method. Then create (or adjust) axis ranges based on these values.
Related tutorials
Demo source
<!-- Styles -->
<style>
#chartdiv {
width: 100%;
height: 500px;
max-width: 100%
}
</style>
<!-- Resources -->
<script src="https://cdn.amcharts.com/lib/5/index.js"></script>
<script src="https://cdn.amcharts.com/lib/5/xy.js"></script>
<script src="https://cdn.amcharts.com/lib/5/themes/Animated.js"></script>
<!-- Chart code -->
<script>
am5.ready(function() {
// Create root element
// https://www.amcharts.com/docs/v5/getting-started/#Root_element
var root = am5.Root.new("chartdiv");
// Set themes
// https://www.amcharts.com/docs/v5/concepts/themes/
root.setThemes([
am5themes_Animated.new(root)
]);
// Create chart
// https://www.amcharts.com/docs/v5/charts/xy-chart/
var chart = root.container.children.push(am5xy.XYChart.new(root, {
panX: false,
panY: false,
wheelX: "panX",
wheelY: "zoomX",
pinchZoomX: true,
paddingLeft: 0
}));
// Add cursor
// https://www.amcharts.com/docs/v5/charts/xy-chart/cursor/
var cursor = chart.set("cursor", am5xy.XYCursor.new(root, {
behavior: "selectX"
}));
cursor.lineY.set("visible", false);
var selectStatedX;
cursor.events.on("selectstarted", function () {
selectStatedX = cursor.getPrivate("positionX");
})
cursor.events.on("selectended", function () {
var selectEndedX = cursor.getPrivate("positionX");
var startValue = xAxis.positionToValue(xAxis.toAxisPosition(selectStatedX));
var endValue = xAxis.positionToValue(xAxis.toAxisPosition(selectEndedX));
// flip if start > end
if (startValue > endValue) {
[startValue, endValue] = [endValue, startValue];
}
var skip = false;
// check for overlapping
var len = xAxis.axisRanges.length;
for (var i = len - 1; i >= 0; i--) {
var axisRange = xAxis.axisRanges.getIndex(i);
var axisRangeStartValue = axisRange.get("value");
var axisRangeEndValue = axisRange.get("endValue");
// flip if start > end
if (axisRangeStartValue > axisRangeEndValue) {
[axisRangeStartValue, axisRangeEndValue] = [axisRangeEndValue, axisRangeStartValue];
}
// if both end and start values are within old range, do not do anything
if (startValue >= axisRangeStartValue && startValue <= axisRangeEndValue && endValue >= axisRangeStartValue && endValue <= axisRangeEndValue) {
skip = true
}
else {
if (startValue >= axisRangeStartValue && startValue <= axisRangeEndValue) {
startValue = axisRangeEndValue;
}
if (endValue >= axisRangeStartValue && endValue <= axisRangeEndValue) {
endValue = axisRangeStartValue;
}
}
// if a new range takes within itself whole old range, remove old range
if (startValue <= axisRangeStartValue && endValue >= axisRangeEndValue) {
xAxis.axisRanges.removeValue(axisRange);
}
}
if (!skip) {
var dataItem = xAxis.makeDataItem({});
dataItem.set("value", startValue);
dataItem.set("endValue", endValue);
xAxis.createAxisRange(dataItem);
dataItem.get("axisFill").setAll({ fill: chart.get("colors").getIndex(7), fillOpacity: 0.4, visible: true });
dataItem.get("grid").set("forceHidden", true);
}
cursor.selection.hide();
})
// Generate random data
var date = new Date();
date.setHours(0, 0, 0, 0);
var value = 100;
function generateData() {
value = Math.round((Math.random() * 10 - 5) + value);
am5.time.add(date, "day", 1);
return {
date: date.getTime(),
value: value
};
}
function generateDatas(count) {
var data = [];
for (var i = 0; i < count; ++i) {
data.push(generateData());
}
return data;
}
// Create axes
// https://www.amcharts.com/docs/v5/charts/xy-chart/axes/
var xAxis = chart.xAxes.push(am5xy.DateAxis.new(root, {
maxDeviation: 0.2,
baseInterval: {
timeUnit: "day",
count: 1
},
renderer: am5xy.AxisRendererX.new(root, {
minGridDistance: 80,
minorGridEnabled: true
}),
tooltip: am5.Tooltip.new(root, {})
}));
var yAxis = chart.yAxes.push(am5xy.ValueAxis.new(root, {
renderer: am5xy.AxisRendererY.new(root, {})
}));
// Add series
// https://www.amcharts.com/docs/v5/charts/xy-chart/series/
var series = chart.series.push(am5xy.LineSeries.new(root, {
name: "Series",
xAxis: xAxis,
yAxis: yAxis,
valueYField: "value",
valueXField: "date",
tooltip: am5.Tooltip.new(root, {
labelText: "{valueY}"
})
}));
// Add scrollbar
// https://www.amcharts.com/docs/v5/charts/xy-chart/scrollbars/
chart.set("scrollbarX", am5.Scrollbar.new(root, {
orientation: "horizontal"
}));
// Set data
var data = generateDatas(1200);
series.data.setAll(data);
// Make stuff animate on load
// https://www.amcharts.com/docs/v5/concepts/animations/
series.appear(1000);
chart.appear(1000, 100);
}); // end am5.ready()
</script>
<!-- HTML -->
<div id="chartdiv"></div>