using ScottPlot.Drawing;
using ScottPlot.Ticks;
using System;
using System.Drawing;
using System.Linq;
namespace ScottPlot.Renderable
{
static class AxisTicksRender
{
private static bool EdgeIsVertical(Edge edge) => (edge == Edge.Left || edge == Edge.Right);
private static bool EdgeIsHorizontal(Edge edge) => (edge == Edge.Top || edge == Edge.Bottom);
public static void RenderGridLines(PlotDimensions dims, Graphics gfx, double[] majorPositions, double[] minorPositions, double[] tickPositionSmajor,
LineStyle gridLineStyle, Color gridLineColor, float gridLineWidth, Edge edge)
{
if (majorPositions is null || majorPositions.Length == 0 || minorPositions is null || minorPositions.Length == 0 || gridLineStyle == LineStyle.None)
return;
// don't draw grid lines on the last pixel to prevent drawing over the data frame
float xEdgeLeft = dims.DataOffsetX + 1;
float xEdgeRight = dims.DataOffsetX + dims.DataWidth - 1;
float yEdgeTop = dims.DataOffsetY + 1;
float yEdgeBottom = dims.DataOffsetY + dims.DataHeight - 1;
if (EdgeIsVertical(edge))
{
//float x = (edge == Edge.Left) ? dims.DataOffsetX : dims.DataOffsetX + dims.DataWidth;
//float x2 = (edge == Edge.Left) ? dims.DataOffsetX + dims.DataWidth : dims.DataOffsetX;
var ys = majorPositions.Select(i => dims.GetPixelY(i)).Where(y => yEdgeTop < y && y < yEdgeBottom);
if (gridLineStyle != LineStyle.None)
using (var pen = GDI.Pen(gridLineColor, gridLineWidth, gridLineStyle))
{
//foreach (float y in ys)
// gfx.DrawLine(pen, x, y, x2, y);
Brush brush = new SolidBrush(gridLineColor);
foreach (var itemx in tickPositionSmajor)
{
foreach (var itemy in minorPositions)
{
gfx.FillRectangle(brush, dims.GetPixelX(itemx), dims.GetPixelY(itemy), 1, 1);
}
foreach (float y in ys)
{
gfx.FillRectangle(brush, dims.GetPixelX(itemx), y, 1, 1);
}
}
}
}
if (EdgeIsHorizontal(edge))
{
//float y = (edge == Edge.Top) ? dims.DataOffsetY : dims.DataOffsetY + dims.DataHeight;
//float y2 = (edge == Edge.Top) ? dims.DataOffsetY + dims.DataHeight : dims.DataOffsetY;
var xs = majorPositions.Select(i => dims.GetPixelX(i)).Where(x => xEdgeLeft < x && x < xEdgeRight);
if (gridLineStyle != LineStyle.None)
using (var pen = GDI.Pen(gridLineColor, gridLineWidth, gridLineStyle))
{
Brush brush = new SolidBrush(gridLineColor);
foreach (var itemy in tickPositionSmajor)
{
foreach (var itemx in minorPositions)
{
gfx.FillRectangle(brush, dims.GetPixelX(itemx), dims.GetPixelY(itemy), 1, 1);
}
foreach (float x in xs)
{
gfx.FillRectangle(brush, x, dims.GetPixelY(itemy), 1, 1);
}
}
}
}
}
public static void RenderTickMarks(PlotDimensions dims, Graphics gfx, double[] positions,double[] tickPositionsMajor, float tickLength, Color tickColor, Edge edge, float pixelOffset)
{
if (positions is null || positions.Length == 0)
return;
if (EdgeIsVertical(edge))
{
float x = (edge == Edge.Left) ? dims.DataOffsetX - pixelOffset : dims.DataOffsetX + dims.DataWidth + pixelOffset;
float tickDelta = (edge == Edge.Left) ? -tickLength : tickLength;
var ys = positions.Select(i => dims.GetPixelY(i));
var tickmajorys = tickPositionsMajor.Select(i => dims.GetPixelY(i));
using (var pen = GDI.Pen(tickColor))
{
foreach (float y in ys)
{
//if (y > dims.DataOffsetY + dims.DataHeight || y < dims.DataOffsetY)
// continue;
gfx.DrawLine(pen, x, y, x - tickDelta, y);
}
foreach (var ty in tickmajorys)
{
gfx.DrawLine(pen, x, ty, x - tickDelta, ty);
}
}
}
if (EdgeIsHorizontal(edge))
{
float y = (edge == Edge.Top) ? dims.DataOffsetY - pixelOffset : dims.DataOffsetY + dims.DataHeight + pixelOffset;
float tickDelta = (edge == Edge.Top) ? -tickLength : tickLength;
var xs = positions.Select(i => dims.GetPixelX(i));
var tickmajorxs = tickPositionsMajor.Select(i => dims.GetPixelX(i));
using (var pen = GDI.Pen(tickColor))
{
foreach (float x in xs)
{
//if (x > dims.DataOffsetX + dims.DataWidth || y < dims.DataOffsetX)
// continue;
gfx.DrawLine(pen, x, y, x, y - tickDelta);
}
foreach (var tx in tickmajorxs)
{
gfx.DrawLine(pen, tx, y, tx, y - tickDelta);
}
}
}
}
///
/// 绘制刻度的label
///
///
///
///
///
///
///
///
///
///
///
///
///
public static void RenderTickLabels(PlotDimensions dims, Graphics gfx, Color axisColor, TickCollection tc, Drawing.Font tickFont, Edge edge, float rotation, bool rulerMode, float PixelOffset, float MajorTickLength, float MinorTickLength, bool rectangle)
{
if (tc.tickLabels is null || tc.tickLabels.Length == 0)
return;
using (var font = GDI.Font(tickFont))
using (var brush = GDI.Brush(tickFont.Color))
using (var sf = GDI.StringFormat())
{
// TODO: Refactor to improve rotated tick label rendering:
// 1) rotation should always be assumed
// 2) a separate function should translate/rotate/render/reset
// 3) all edges should support rotation
if (edge == Edge.Bottom)//画在底部
{
sf.Alignment = rulerMode ? StringAlignment.Near : StringAlignment.Center;
sf.LineAlignment = StringAlignment.Near;
for (int i = 0; i < tc.tickPositionsMajor.Length; i++)
{
if (rectangle)
{
gfx.FillRectangle(GDI.Brush(Color.Black),
x: dims.GetPixelX(tc.tickPositionsMajor[i]) - tc.tickLabels[i].Length * font.Height / 4,
y: dims.DataOffsetY + dims.DataHeight - PixelOffset - MajorTickLength - font.Height,
width: tc.tickLabels[i].Length * font.Height / 2,
height: font.Height + 2);
}
gfx.DrawString(tc.tickLabels[i], font, GDI.Brush(axisColor), format: sf,
x: dims.GetPixelX(tc.tickPositionsMajor[i]),
y: dims.DataOffsetY + dims.DataHeight - PixelOffset - MajorTickLength - font.Height);
}
}
else if (edge == Edge.Top)//画在上部
{
sf.Alignment = rulerMode ? StringAlignment.Near : StringAlignment.Center;
sf.LineAlignment = StringAlignment.Near;
for (int i = 0; i < tc.tickPositionsMajor.Length; i++)
gfx.DrawString(tc.tickLabels[i], font, GDI.Brush(axisColor), format: sf,
x: dims.GetPixelX(tc.tickPositionsMajor[i]),
y: dims.DataOffsetY + PixelOffset - MajorTickLength + 10 + font.Height);
}
else if (edge == Edge.Left)//画在左方
{
sf.LineAlignment = rulerMode ? StringAlignment.Far : StringAlignment.Center;
sf.Alignment = StringAlignment.Near;
for (int i = 0; i < tc.tickPositionsMajor.Length; i++)
gfx.DrawString(tc.tickLabels[i], font, GDI.Brush(axisColor), format: sf,
x: dims.DataOffsetX + PixelOffset + 40,
y: dims.GetPixelY(tc.tickPositionsMajor[i]));
}
else if (edge == Edge.Right)//画在右方
{
sf.LineAlignment = rulerMode ? StringAlignment.Far : StringAlignment.Center;
sf.Alignment = StringAlignment.Far;
for (int i = 0; i < tc.tickPositionsMajor.Length; i++)
{
var maxLabelSize = GDI.MeasureString(tc.tickLabels[i].Trim(), tickFont);
if (rectangle)
{
gfx.FillRectangle(GDI.Brush(Color.Black),
x: dims.DataOffsetX + dims.DataWidth - PixelOffset - 34 - maxLabelSize.Width,
y: dims.GetPixelY(tc.tickPositionsMajor[i]) - font.Height / 2 - 3,
width: tc.tickLabels[i].Length * font.Height / 2,
height: font.Height + 2);
}
gfx.DrawString(tc.tickLabels[i], font, GDI.Brush(axisColor), format: sf,
x: dims.DataOffsetX - PixelOffset - 30 + dims.DataWidth,
y: dims.GetPixelY(tc.tickPositionsMajor[i]));
}
}
else
{
throw new NotImplementedException();
}
}
}
}
}