更新时间:2023-02-02 17:07:07
这是一个好主意.
最简单的方法是在图表的Paint
事件(可能是PrePaint
)中绘制图像.
The simplest way is to draw the image in a Paint
event of the Chart, maybe PrePaint
.
Let's go to work.. We will use the DrawImage
overload that allows us zooming as well as cropping. For this we need two rectangles.
第一个挑战是始终获得正确的目标矩形.
The first challenge is to always get the correct target rectangle.
为此,我们需要将InnerPlotPosition
从相对位置转换为绝对像素.
For this we need to convert the InnerPlotPosition
from relative positions to absolute pixels.
这两个功能会有所帮助:
These two functions will help:
RectangleF ChartAreaClientRectangle(Chart chart, ChartArea CA)
{
RectangleF CAR = CA.Position.ToRectangleF();
float pw = chart.ClientSize.Width / 100f;
float ph = chart.ClientSize.Height / 100f;
return new RectangleF(pw * CAR.X, ph * CAR.Y, pw * CAR.Width, ph * CAR.Height);
}
RectangleF InnerPlotPositionClientRectangle(Chart chart, ChartArea CA)
{
RectangleF IPP = CA.InnerPlotPosition.ToRectangleF();
RectangleF CArp = ChartAreaClientRectangle(chart, CA);
float pw = CArp.Width / 100f;
float ph = CArp.Height / 100f;
return new RectangleF(CArp.X + pw * IPP.X, CArp.Y + ph * IPP.Y,
pw * IPP.Width, ph * IPP.Height);
}
使用这些数字设置目标矩形非常简单:
With these numbers setting the destination rectangle is as simple as:
Rectangle tgtR = Rectangle.Round(new RectangleF(ipr.Left, ipr.Bottom - 15, ipr.Width, 15));
您可以根据需要选择一个高度.
You can chose a height as you like..
下一个挑战是源矩形.
不缩放就简单地是:
Rectangle srcR = new Rectangle( 0, 0, bmp.Width, bmp.Height);
但是对于缩放和平移,我们需要对其进行缩放;为此,我们可以使用x轴和ScaleView
的Minimum
和Maximum
值.
But for zooming and panning we need to scale it; for this we can use the x-axis and the ScaleView
's Minimum
and Maximum
values.
我们计算轴上第一个点和最后一个点的因子:
We calculate factors for the first and last spot on the axis:
double f1 = ax.ScaleView.ViewMinimum / (ax.Maximum - ax.Minimum);
double f2 = ax.ScaleView.ViewMaximum / (ax.Maximum - ax.Minimum);
现在我们得到的源矩形可能是这样的:
now we get the source rectangle maybe like this:
int x = (int)(bmp.Width * f1);
int xx = (int)(bmp.Width * f2);
Rectangle srcR = new Rectangle( x, 0, xx - x, bmp.Height);
让我们放在一起:
private void chart_PrePaint(object sender, ChartPaintEventArgs e)
{
// a few short names
Graphics g = e.ChartGraphics.Graphics;
ChartArea ca = chart.ChartAreas[0];
Axis ax = ca.AxisX;
// pixels of plot area
RectangleF ipr = InnerPlotPositionClientRectangle(chart, ca);
// scaled first and last position
double f1 = ax.ScaleView.ViewMinimum / (ax.Maximum - ax.Minimum);
double f2 = ax.ScaleView.ViewMaximum / (ax.Maximum - ax.Minimum);
// actual drawing with the zooming overload
using (Bitmap bmp = (Bitmap)Bitmap.FromFile(imagePath))
{
int x = (int)(bmp.Width * f1);
int xx = (int)(bmp.Width * f2);
Rectangle srcR = new Rectangle( x, 0, xx - x, bmp.Height);
Rectangle tgtR = Rectangle.Round(
new RectangleF(ipr.Left , ipr.Bottom - 15, ipr.Width, 15));
g.DrawImage(bmp, tgtR, srcR, GraphicsUnit.Pixel);
}
}
一些注意事项:
我当然建议使用Image资源,而不是总是从磁盘加载!
Of course I would recomend to use an Image resource instead of always loading from disk!
图形将始终覆盖数据点以及网格.你也可以.
The Drawing will always overlay the data points and also the grids. You can either..
ax.LineWidth = 10
ax.LineWidth = 10
对于后一种解决方案,您可能希望根据缩放状态偏移y位置.又快又脏:int yoff = (ax.ScaleView.IsZoomed ? 12 : 5);
.为了避免出现黑色条纹,还应将轴设置为透明"或"chart.BackColor ..
For the latter solution you would want to offset the y-position depending on the zoom state. Quick and dirty: int yoff = (ax.ScaleView.IsZoomed ? 12 : 5);
. To avoid black stripes also make the axis Transparent or chart.BackColor..
更新:
您还可以还原为使用StripLine
.它可以缩放其BackgroundImage
,并且每当更改比例视图时(即缩放或平移时),您都必须创建合适的图像.为此,上面的许多代码将用于创建新图像.请参阅这篇文章,以了解如何在图表中添加和替换不同的NamedImage
! (有关标记图像的相关部分接近结尾!)
You can also revert to using a StripLine
. It can scale its BackgroundImage
and you would have to create a suitable image whenever changing the scaleview, i.e. when zooming or panning. For this much of the above code would be used to create the new images. See this post for examples of adding and replacing varying NamedImage
to a Chart! (The relevant portion is close to the end about the marker images!)
事实上,我找到了***的解决方案,并添加了第二个答案.
In fact I found that way the best solution and have added a second answer.