I'm trying to make my own custom panning feature in MSCharts (Microsoft Charting Controls). I realize there is an extension for zooming and panning, however it doesn't have a lot of the capabilities that I want it to have. Here is the panning function that I have currently:
//handles mouse panning, will pan while mouse left click if held down..
private int prevx = 0;
private int prevy = 0;
private void Mouse_Up(object sender, MouseEventArgs e)
{
//reset previous x and y on mouse click up
if (e.Button == MouseButtons.Left)
{
prevx = 0;
prevy = 0;
}
}
private void Mouse_Move(object sender, MouseEventArgs e, Chart chart)
{
//if mouse was moved and mouse left click
if (e.Button == MouseButtons.Left)
{
//a scalar, not entirely sure how useful it is, only works for my viewport
double incr = 0.00130;
if (prevx != 0 && prevy != 0)
{
//find x and y difference in mouse movement
int diffx = e.X - prevx;
int diffy = e.Y - prevy;
//how much to increment x and y
double incrx = incr * Math.Abs(diffx);
double incry = incr * Math.Abs(diffy);
//get chart mins and maxs for both axes
double minX = chart.ChartAreas[0].AxisX.Minimum;
double maxX = chart.ChartAreas[0].AxisX.Maximum;
double minY = chart.ChartAreas[0].AxisY.Minimum;
double maxY = chart.ChartAreas[0].AxisY.Maximum;
if (diffx > 0 && diffy > 0)
{
chart.ChartAreas[0].AxisX.Minimum -= (maxX - minX) * incrx;
chart.ChartAreas[0].AxisX.Maximum -= (maxX - minX) * incrx;
chart.ChartAreas[0].AxisY.Minimum += (maxY - minY) * incry;
chart.ChartAreas[0].AxisY.Maximum += (maxY - minY) * incry;
//Console.WriteLine("upleft");
}
else if (diffx < 0 && diffy > 0)
{
chart.ChartAreas[0].AxisX.Minimum += (maxX - minX) * incrx;
chart.ChartAreas[0].AxisX.Maximum += (maxX - minX) * incrx;
chart.ChartAreas[0].AxisY.Minimum += (maxY - minY) * incry;
chart.ChartAreas[0].AxisY.Maximum += (maxY - minY) * incry;
//Console.WriteLine("upright");
}
else if (diffx > 0 && diffy < 0)
{
chart.ChartAreas[0].AxisX.Minimum -= (maxX - minX) * incrx;
chart.ChartAreas[0].AxisX.Maximum -= (maxX - minX) * incrx;
chart.ChartAreas[0].AxisY.Minimum -= (maxY - minY) * incry;
chart.ChartAreas[0].AxisY.Maximum -= (maxY - minY) * incry;
//Console.WriteLine("bottom left");
}
else if (diffx < 0 && diffy < 0)
{
chart.ChartAreas[0].AxisX.Minimum += (maxX - minX) * incrx;
chart.ChartAreas[0].AxisX.Maximum += (maxX - minX) * incrx;
chart.ChartAreas[0].AxisY.Minimum -= (maxY - minY) * incry;
chart.ChartAreas[0].AxisY.Maximum -= (maxY - minY) * incry;
//Console.WriteLine("bottomright");
}
else if (diffx > 0 && diffy == 0)
{
chart.ChartAreas[0].AxisX.Minimum -= (maxX - minX) * incrx;
chart.ChartAreas[0].AxisX.Maximum -= (maxX - minX) * incrx;
//Console.WriteLine("right");
}
else if (diffx < 0 && diffy == 0)
{
chart.ChartAreas[0].AxisX.Minimum += (maxX - minX) * incrx;
chart.ChartAreas[0].AxisX.Maximum += (maxX - minX) * incrx;
//Console.WriteLine("left");
}
else if (diffy > 0 && diffx == 0)
{
chart.ChartAreas[0].AxisY.Minimum += (maxY - minY) * incry;
chart.ChartAreas[0].AxisY.Maximum += (maxY - minY) * incry;
//Console.WriteLine("down");
}
else if (diffy < 0 && diffx == 0)
{
chart.ChartAreas[0].AxisY.Minimum -= (maxY - minY) * incry;
chart.ChartAreas[0].AxisY.Maximum -= (maxY - minY) * incry;
//Console.WriteLine("up");
}
}
prevx = e.X;
prevy = e.Y;
}
}
I noticed there was a similar question, though it was in JavaFX, which I have no experience in. The panning feature that I envision is supposed to be able to move the mouse with the graph. So if I clicked on a certain point, dragged left 50px, that same point will still be directly under my mouse. In my current viewport, this works. However, if I make the graph smaller or larger, things don't work. When the graph becomes smaller, the graph moves slower than my mouse, and when the graph gets bigger, the graph moves faster than my mouse.
I know I should probably somehow include the viewport or chart width into the calculation, but I really just don't know how. Do any of you have experience with this? Thanks.
You are quite right in doubting the 'scalar' approach to calculate values from pixels by a factor. This will never work and for more than one reason..
But the correct solution is so much simpler anyway. It makes use of one of the axis conversion functions to convert between data values and pixel positions. (There is also one to convert to and from percent positions, btw..)
I store the initial position to avoid rounding errors during the mouse move:
All we need now is the
Mousedown
:And the much simpler
MouseMove
:One of the problems with a scaling calculation is that you may want to resize the chart; after that the scale will no longer work. Another is that you would have to take out the stuff outside of the
ChartArea
, and theInnerPlotPosition
, i.e. theAxis.Labels
,Titles
and theLegend
since the space they take shouldn't be scaled..Note the the axis functions are only valid during
Paintxxx
orMousexxx
events..Here is the result: