From Jan to MayUse left and right arrows to move selectionFrom JanUse left and right arrows to move left selectionTo MayUse left and right arrows to move right selectionUse TAB to select grip buttons or left and right arrows to change selection100%Chart created using amCharts library
  • Open in:

Drawing chart series with mouse or touch

Your charts don’t have to be limited to passively displaying data. You can use amCharts as an interactive chart creation surface and enable your users to visually draw new charts. Click anywhere on plot area to draw the new series, drag bullets to adjust positions.

Demo source

<!-- Styles -->
<style>
#chartdiv {
  width: 100%;
  height: 500px;
}


.ampopup-content {
  background: rgb(60, 171, 255)!important;
  background-color: rgba(60, 171, 255, 0.8)!important;
}
</style>

<!-- Resources -->
<script src="https://cdn.amcharts.com/lib/4/core.js"></script>
<script src="https://cdn.amcharts.com/lib/4/charts.js"></script>
<script src="https://cdn.amcharts.com/lib/4/themes/animated.js"></script>

<!-- Chart code -->
<script>
am4core.ready(function() {

// Themes begin
am4core.useTheme(am4themes_animated);
// Themes end



var chart = am4core.create("chartdiv", am4charts.XYChart);
chart.paddingRight = 20;

var data = [];
var visits = 10;
for (var i = 1; i < 500; i++) {
  visits += Math.round((Math.random() < 0.5 ? 1 : -1) * Math.random() * 10);
  data.push({ date: new Date(2018, 0, i, 0,0,0,0), value: visits });
}

chart.data = data;

var popup = chart.openPopup("<div>Click on plot area to add points<br>Drag bullets to change values<br>Double click on bullet to remove</div>");
popup.top = 60;
popup.right = 30;
popup.defaultStyles = false;


var dateAxis = chart.xAxes.push(new am4charts.DateAxis());
dateAxis.renderer.grid.template.location = 0;
dateAxis.renderer.minGridDistance = 60;

var valueAxis = chart.yAxes.push(new am4charts.ValueAxis());
//valueAxis.tooltip.disabled = true;
valueAxis.renderer.minWidth = 35;

var series = chart.series.push(new am4charts.LineSeries());
series.dataFields.dateX = "date";
series.dataFields.valueY = "value";
//series.tooltipText = "{valueY}";
series.tooltip.pointerOrientation = "vertical";
series.tooltip.background.fillOpacity = 0.5;

chart.cursor = new am4charts.XYCursor();
chart.cursor.xAxis = dateAxis;
chart.cursor.behavior = "none";

var scrollbarX = new am4core.Scrollbar();
chart.scrollbarX = scrollbarX;

var newSeries;
var addingPointsDisabled = false;

addSeries();

function addSeries() {
  newSeries = chart.series.push(new am4charts.LineSeries())
  newSeries.data = []
  newSeries.dataFields.dateX = "date";
  newSeries.dataFields.valueY = "newValue";
  newSeries.interpolationDuration = 0;

  var bullet = newSeries.bullets.push(new am4charts.CircleBullet());
  bullet.draggable = true;

  bullet.events.on("dragged", function(event) {
    var bullet = event.target;
            
    var x = bullet.pixelX; 
    //x = dateAxis.getX(bullet.dataItem, "dateX"); //  uncomment this line if you want to allow draggin bullets only along y axis

    bullet.moveTo({ x: x, y: bullet.pixelY }, undefined, undefined, true);
    bullet.dataItem.valueY = valueAxis.yToValue(bullet.pixelY);
    bullet.dataItem.dataContext.newValue = bullet.dataItem.valueY;

    // remove the following three lines if you want to allow draggin bullets only along y axis
    bullet.dataItem.dateX = dateAxis.xToValue(bullet.pixelX);    
    bullet.dataItem.dataContext.date = bullet.dataItem.dateX;    
    dateAxis.postProcessSeriesDataItem(bullet.dataItem);
  })

  bullet.events.on("down", function(event) {
    addingPointsDisabled = true;

    chart.cursor.triggerMove(
      { x: series.tooltipX, y: series.tooltipY },
      "hard"
    ); // sticks cursor to the point

  })


  bullet.events.on("dragstop", function(event) {

    var bullet = event.target;

    chart.cursor.triggerMove(
      { x: series.tooltipX, y: series.tooltipY },
      "none"
    ); // enables mouse following again

    addingPointsDisabled = false;
  })

  bullet.events.on("doublehit", function(event) {
    addingPointsDisabled = false;
    var dataItem = event.target.dataItem;
    var dataContext = dataItem.dataContext;
    newSeries.data.splice(newSeries.data.indexOf(dataContext), 1);
    newSeries.invalidateData();

    chart.cursor.triggerMove(
      { x: series.tooltipX, y: series.tooltipY },
      "none"
    ); // enables mouse following again    
  })
}


var interaction = am4core.getInteraction();

interaction.events.on("up", function(event) {
  if (newSeries && !addingPointsDisabled && chart.cursor.visible) {
    var date = series.tooltipDataItem.dateX;
    var point = am4core.utils.documentPointToSprite(event.pointer.point, chart.seriesContainer);
    var value = valueAxis.yToValue(point.y);
    if (value > valueAxis.min && value < valueAxis.max) {
      newSeries.data.push({ date: date, newValue: value });
      sortData();
      newSeries.invalidateData();
    }
  }
})

function sortData() {
  newSeries.data.sort(function(a, b) {
    var atime = a.date.getTime();
    var btime = b.date.getTime();

    if (atime < btime) {
      return -1;
    }
    else if (atime == btime) {
      return 0;
    }
    else {
      return 1;
    }
  })
}

}); // end am4core.ready()
</script>

<!-- HTML -->
<div id="chartdiv"></div>