Resize Column on drag

In this tutorial we describe how to change dataPoint value by dragging and reposition them.

Here are the steps:

Step1:

Create a basic chart with required options. And call chart.render() method to render the chart.

var chart = new CanvasJS.Chart("chartContainer",{
	title :{
		text: "Try dragging column to reposition dataPoint"
	},
	data: [{
		type: "column",
		dataPoints : [
			{ label: "apple",  y: 10  },
			{ label: "orange", y: 15  },
			{ label: "banana", y: 25  },
			{ label: "mango",  y: 30  },
			{ label: "grape",  y: 28  }
		]
	}]
});
chart.render();

Step2:

Attach event handlers to div with id “chartContainer” so as to perform necessary actions when user clicks or drags inside the div.

$("#chartContainer > .canvasjs-chart-container").on({
        mousedown: function(e) {
	     //Perform actions of Step3 and Step4 here
	},
	mouseMove: function(e) {
	     //Perform actions of Step5 here
	}, 
	mouseUp: function(e) {
	     //Perform actions of Step6 here
        }
});

Step3:

Get the co-ordinates of mouse event inside the div. Convert the obtained pixel co-ordinates (relX, relY) to axis values using convertPixelToValue method so that it can be used to check which dataPoint is being dragged.

var parentOffset = $("#chartContainer > .canvasjs-chart-container").offset();
var relX = e.pageX - parentOffset.left;
var relY = e.pageY - parentOffset.top;
xValue = Math.round(chart.axisX[0].convertPixelToValue(relX));
yValue = Math.round(chart.axisY[0].convertPixelToValue(relY));

Step4:

Search for above obtained values (xValue and yValue) in the existing dataPoints. If it matches with any of the dataPoint, and mousedown event is already triggered, store the index number of the matched dataPoint in some variable (say, selected). But if the mousedown event is not triggered while the cursor position is still on some dataPoint, just set the changeCursor flag to true. In order to snap mouse to nearby dataPoint, set xSnapDistance and ySnapDistance.

var xSnapDistance = chart.axisX[0].convertPixelToValue(chart.get("dataPointWidth")) / 2;
var ySnapDistance = 3;

function searchDataPoint() {
	var dps = chart.data[0].dataPoints;
	for(var i = 0; i < dps.length; i++ ) {
		if( (xValue >= dps[i].x - xSnapDistance && xValue <= dps[i].x + xSnapDistance) && 
		  (yValue >= dps[i].y - ySnapDistance && yValue <= dps[i].y + ySnapDistance) ) {
			if(mouseDown) {
				selected = i;
				break;
			}
			else {
				changeCursor = true;
				break; 
			}
		}
		else {
			selected = null;
			changeCursor = false;
		}
	}
}

Step5:

On mousemove, check if mouseDown is set to true. If it is set and index of selected dataPoint is stored in selected variable, get the current position of mouse as shown in Step 3 and update dataPoint value to that new position. After updating the dataPoint, re-render the chart to show the changes.

if(mouseDown) {
	clearTimeout(timerId);
	timerId = setTimeout(function(){
		if(selected != null) {
			chart.data[0].dataPoints[selected].y = yValue;
			chart.render();
		}   
	}, 0);
}

If mouseDown is not set, get the current location of cursor and check if changeCursor is set to true. If the cursor is on any of the dataPoint, change the cursor type to "n-resize", otherwise to "default".

else {
	searchDataPoint();
	if(changeCursor) {
		chart.data[0].set("cursor", "n-resize");
	}
	else {
		chart.data[0].set("cursor", "default");
	}
}

Step6:

On mouseup event, set the selected variable back to null and mouseDown flag to false.

selected = null;
mouseDown = false;

Finalising

To summarize, we have to check if mouse is on any dataPoint while being dragged. If yes, update the dataPoint's value accordingly and re-render the chart.

Below is the compilation of final code.

Try it Yourself by Editing the Code below.


If you have any questions, please feel free to ask in our forums.Ask Question