public override void Render(Settings settings) { if (label is null) { return; } SizeF size = GDI.MeasureString(settings.gfxData, label, font); double x = (xPixel >= 0) ? xPixel : settings.bmpData.Width + xPixel - size.Width; double y = (yPixel >= 0) ? yPixel : settings.bmpData.Height + yPixel - size.Height; PointF location = new PointF((float)x, (float)y); if (fill && shadow) { settings.gfxData.FillRectangle(shadowBrush, location.X + 5, location.Y + 5, size.Width, size.Height); } if (fill) { settings.gfxData.FillRectangle(fillBrush, location.X, location.Y, size.Width, size.Height); } if (pen.Width > 0) { settings.gfxData.DrawRectangle(pen, location.X, location.Y, size.Width, size.Height); } settings.gfxData.DrawString(label, font, fontBrush, location); }
public override void Render(Settings settings) { float widthPx = (float)(sizeX * settings.xAxisScale); float heightPx = (float)(sizeY * settings.yAxisScale); using (var font = new Font(fontName, (float)fontSize, fontStyle)) using (var brush = new SolidBrush(color)) using (var pen = new Pen(color, (float)thickness)) { PointF cornerPoint = settings.GetPixel(settings.axes.x.Max, settings.axes.y.Min); cornerPoint.X -= (float)padPx; cornerPoint.Y -= (float)padPx; var xLabelSize = GDI.MeasureString(settings.gfxData, labelX, font); var yLabelSize = GDI.MeasureString(settings.gfxData, labelY, font); cornerPoint.X -= yLabelSize.Width * 1.2f; cornerPoint.Y -= yLabelSize.Height; PointF horizPoint = new PointF(cornerPoint.X - widthPx, cornerPoint.Y); PointF vertPoint = new PointF(cornerPoint.X, cornerPoint.Y - heightPx); PointF horizMidPoint = new PointF((cornerPoint.X + horizPoint.X) / 2, cornerPoint.Y); PointF vertMidPoint = new PointF(cornerPoint.X, (cornerPoint.Y + vertPoint.Y) / 2); settings.gfxData.DrawLines(pen, new PointF[] { horizPoint, cornerPoint, vertPoint }); settings.gfxData.DrawString(labelX, font, brush, horizMidPoint.X, cornerPoint.Y, settings.misc.sfNorth); settings.gfxData.DrawString(labelY, font, brush, cornerPoint.X, vertMidPoint.Y, settings.misc.sfWest); } }
private void RecalculatePositionsAutomaticDatetime(Settings settings) { // the goal of this function is to set tickPositionsMajor, tickLabels, tickPositionsMinor, cornerLabel, and maxLabelSize double low, high; int tickCount; // predict maxLabelSize up front using predetermined label sizes maxLabelSize = GDI.MeasureString(settings.gfxData, "2019-08-20\n8:42:17 PM", settings.ticks.font); if (verticalAxis) { low = settings.axes.y.Min - settings.yAxisUnitsPerPixel; // add an extra pixel to capture the edge tick high = settings.axes.y.Max + settings.yAxisUnitsPerPixel; // add an extra pixel to capture the edge tick tickCount = (int)(settings.dataSize.Height / maxLabelSize.Height); } else { low = settings.axes.x.Min - settings.xAxisUnitsPerPixel; // add an extra pixel to capture the edge tick high = settings.axes.x.Max + settings.xAxisUnitsPerPixel; // add an extra pixel to capture the edge tick tickCount = (int)(settings.dataSize.Width / maxLabelSize.Width); } if (low < high) { low = Math.Max(low, DateTime.MinValue.ToOADate()); high = Math.Min(high, DateTime.MaxValue.ToOADate()); var dtManualUnits = (verticalAxis) ? settings.ticks.manualDateTimeSpacingUnitY : settings.ticks.manualDateTimeSpacingUnitX; var dtManualSpacing = (verticalAxis) ? settings.ticks.manualSpacingY : settings.ticks.manualSpacingX; var dateTicks = DateTimeTicks.GetTicks(DateTime.FromOADate(low), DateTime.FromOADate(high), tickCount, settings.culture, dtManualUnits, (int)dtManualSpacing); tickPositionsMajor = Tools.DateTimesToDoubles(dateTicks.Item1); tickLabels = dateTicks.Item2; for (int i = 0; i < tickLabels.Length; i++) { if (tickLabels[i].Contains(", ")) { tickLabels[i] = tickLabels[i].Replace(", ", "\n"); } else { tickLabels[i] += "\n "; // auto-layout works better if dates are always two lines } } } else { tickPositionsMajor = new double[] { }; } // dont forget to set all the things tickPositionsMinor = null; cornerLabel = null; maxLabelSize = LargestLabel(settings, tickLabels); }
public SizeF LargestLabel(Settings settings, string[] labels) { SizeF max = new SizeF(0, 0); foreach (string label in labels) { SizeF tickLabelSize = GDI.MeasureString(settings.gfxData, label, settings.ticks.font); max.Width = Math.Max(max.Width, tickLabelSize.Width); max.Height = Math.Max(max.Height, tickLabelSize.Height); } return(max); }
private static void RenderTickMultipliers(Settings settings) { Brush brush = new SolidBrush(settings.ticks.colour); if ((settings.ticks.x.cornerLabel != "") && settings.ticks.displayXmajor) { SizeF multiplierLabelXsize = GDI.MeasureString(settings.gfxFigure, settings.ticks.x.cornerLabel, settings.ticks.font); settings.gfxFigure.DrawString(settings.ticks.x.cornerLabel, settings.ticks.font, brush, settings.dataOrigin.X + settings.dataSize.Width, settings.dataOrigin.Y + settings.dataSize.Height + multiplierLabelXsize.Height, settings.misc.sfNorthEast); } if ((settings.ticks.y.cornerLabel != "") && settings.ticks.displayYmajor) { settings.gfxFigure.DrawString(settings.ticks.y.cornerLabel, settings.ticks.font, brush, settings.dataOrigin.X, settings.dataOrigin.Y, settings.misc.sfSouthWest); } }
public void Resize(int width, int height, bool useMeasuredStrings = false) { if (useMeasuredStrings && gfxData != null) { // this section was added before display scaling issues (pixel-referenced font sizes) were figured out. // it is probably not needed... string sampleString = "IPjg8.8"; layout.yLabelWidth = (int)GDI.MeasureString(gfxData, sampleString, yLabel.font).Height; layout.y2LabelWidth = (int)GDI.MeasureString(gfxData, sampleString, yLabel.font).Height; // currently y2 isn't supported layout.titleHeight = (int)GDI.MeasureString(gfxData, sampleString, title.font).Height; layout.xLabelHeight = (int)GDI.MeasureString(gfxData, sampleString, xLabel.font).Height; var tickSize = GDI.MeasureString(gfxData, "0.001", ticks.font); layout.yScaleWidth = (int)tickSize.Width; layout.y2ScaleWidth = (int)tickSize.Height; // currently y2 isn't supported layout.xScaleHeight = (int)tickSize.Height; } layout.Update(width, height); if (axes.equalAxes) { var limits = new AxisLimits2D(axes.ToArray()); double xUnitsPerPixel = limits.xSpan / dataSize.Width; double yUnitsPerPixel = limits.ySpan / dataSize.Height; if (yUnitsPerPixel > xUnitsPerPixel) { axes.Zoom(xUnitsPerPixel / yUnitsPerPixel, 1); } else { axes.Zoom(1, yUnitsPerPixel / xUnitsPerPixel); } } }
public static void DrawMarker(Graphics gfx, PointF pixelLocation, MarkerShape shape, float size, Color color) { Pen pen = new Pen(color); Brush brush = new SolidBrush(color); PointF corner1 = new PointF(pixelLocation.X - size / 2, pixelLocation.Y - size / 2); PointF corner2 = new PointF(pixelLocation.X + size / 2, pixelLocation.Y + size / 2); SizeF bounds = new SizeF(size, size); RectangleF rect = new RectangleF(corner1, bounds); switch (shape) { case MarkerShape.filledCircle: gfx.FillEllipse(brush, rect); break; case MarkerShape.openCircle: gfx.DrawEllipse(pen, rect); break; case MarkerShape.filledSquare: gfx.FillRectangle(brush, rect); break; case MarkerShape.openSquare: gfx.DrawRectangle(pen, corner1.X, corner1.Y, size, size); break; case MarkerShape.filledDiamond: // Create points that define polygon. PointF point1 = new PointF(pixelLocation.X, pixelLocation.Y + size / 2); PointF point2 = new PointF(pixelLocation.X - size / 2, pixelLocation.Y); PointF point3 = new PointF(pixelLocation.X, pixelLocation.Y - size / 2); PointF point4 = new PointF(pixelLocation.X + size / 2, pixelLocation.Y); PointF[] curvePoints = { point1, point2, point3, point4 }; //Draw polygon to screen gfx.FillPolygon(brush, curvePoints); break; case MarkerShape.openDiamond: // Create points that define polygon. PointF point5 = new PointF(pixelLocation.X, pixelLocation.Y + size / 2); PointF point6 = new PointF(pixelLocation.X - size / 2, pixelLocation.Y); PointF point7 = new PointF(pixelLocation.X, pixelLocation.Y - size / 2); PointF point8 = new PointF(pixelLocation.X + size / 2, pixelLocation.Y); PointF[] curvePoints2 = { point5, point6, point7, point8 }; //Draw polygon to screen gfx.DrawPolygon(pen, curvePoints2); break; case MarkerShape.asterisk: Font drawFont = new Font("CourierNew", size * 3); SizeF textSize = GDI.MeasureString(gfx, "*", drawFont); PointF asteriskPoint = new PointF(pixelLocation.X - textSize.Width / 2, pixelLocation.Y - textSize.Height / 4); gfx.DrawString("*", drawFont, brush, asteriskPoint); break; case MarkerShape.hashTag: Font drawFont2 = new Font("CourierNew", size * 2); SizeF textSize2 = GDI.MeasureString(gfx, "#", drawFont2); PointF asteriskPoint2 = new PointF(pixelLocation.X - textSize2.Width / 2, pixelLocation.Y - textSize2.Height / 3); gfx.DrawString("#", drawFont2, brush, asteriskPoint2); break; case MarkerShape.cross: Font drawFont3 = new Font("CourierNew", size * 2); SizeF textSize3 = GDI.MeasureString(gfx, "+", drawFont3); PointF asteriskPoint3 = new PointF(pixelLocation.X - textSize3.Width / (5 / 2), pixelLocation.Y - textSize3.Height / 2); gfx.DrawString("+", drawFont3, brush, asteriskPoint3); break; case MarkerShape.eks: Font drawFont4 = new Font("CourierNew", size * 2); SizeF textSize4 = GDI.MeasureString(gfx, "x", drawFont4); PointF asteriskPoint4 = new PointF(pixelLocation.X - textSize4.Width / (5 / 2), pixelLocation.Y - textSize4.Height / 2); gfx.DrawString("x", drawFont4, brush, asteriskPoint4); break; case MarkerShape.verticalBar: Font drawFont5 = new Font("CourierNew", size * 2); SizeF textSize5 = GDI.MeasureString(gfx, "|", drawFont5); PointF asteriskPoint5 = new PointF(pixelLocation.X - textSize5.Width / (5 / 2), pixelLocation.Y - textSize5.Height / 2); gfx.DrawString("|", drawFont5, brush, asteriskPoint5); break; case MarkerShape.triUp: // Create points that define polygon. PointF point9 = new PointF(pixelLocation.X, pixelLocation.Y - size); PointF point10 = new PointF(pixelLocation.X, pixelLocation.Y); PointF point11 = new PointF(pixelLocation.X - size * (float)0.866, pixelLocation.Y + size * (float)0.5); PointF point12 = new PointF(pixelLocation.X, pixelLocation.Y); PointF point13 = new PointF(pixelLocation.X + size * (float)0.866, (pixelLocation.Y + size * (float)0.5)); PointF[] curvePoints3 = { point12, point9, point10, point11, point12, point13 }; //Draw polygon to screen gfx.DrawPolygon(pen, curvePoints3); break; case MarkerShape.triDown: // Create points that define polygon. PointF point14 = new PointF(pixelLocation.X, pixelLocation.Y + size); PointF point15 = new PointF(pixelLocation.X, pixelLocation.Y); PointF point16 = new PointF(pixelLocation.X - size * (float)0.866, pixelLocation.Y - size * (float)0.5); PointF point17 = new PointF(pixelLocation.X, pixelLocation.Y); PointF point18 = new PointF(pixelLocation.X + size * (float)0.866, (pixelLocation.Y - size * (float)0.5)); PointF[] curvePoints4 = { point17, point14, point15, point16, point17, point18 }; //Draw polygon to screen gfx.DrawPolygon(pen, curvePoints4); break; case MarkerShape.none: break; default: throw new NotImplementedException($"unsupported marker type: {shape}"); } }
public override void Render(Settings settings) { PointF defaultPoint = settings.GetPixel(x, y); PointF textLocationPoint = new PointF(); SizeF stringSize = GDI.MeasureString(settings.gfxData, text, font); if (rotation == 0) { switch (alignment) { case TextAlignment.lowerCenter: textLocationPoint.Y = defaultPoint.Y - stringSize.Height; textLocationPoint.X = defaultPoint.X - stringSize.Width / 2; break; case TextAlignment.lowerLeft: textLocationPoint.Y = defaultPoint.Y - stringSize.Height; textLocationPoint.X = defaultPoint.X; break; case TextAlignment.lowerRight: textLocationPoint.Y = defaultPoint.Y - stringSize.Height; textLocationPoint.X = defaultPoint.X - stringSize.Width; break; case TextAlignment.middleLeft: textLocationPoint.Y = defaultPoint.Y - stringSize.Height / 2; textLocationPoint.X = defaultPoint.X; break; case TextAlignment.middleRight: textLocationPoint.Y = defaultPoint.Y - stringSize.Height / 2; textLocationPoint.X = defaultPoint.X - stringSize.Width; break; case TextAlignment.upperCenter: textLocationPoint.Y = defaultPoint.Y; textLocationPoint.X = defaultPoint.X - stringSize.Width / 2; break; case TextAlignment.upperLeft: textLocationPoint = defaultPoint; break; case TextAlignment.upperRight: textLocationPoint.Y = defaultPoint.Y; textLocationPoint.X = defaultPoint.X - stringSize.Width; break; case TextAlignment.middleCenter: textLocationPoint.Y = defaultPoint.Y - stringSize.Height / 2; textLocationPoint.X = defaultPoint.X - stringSize.Width / 2; break; } } else { // ignore alignment if rotation is used textLocationPoint = new PointF(defaultPoint.X, defaultPoint.Y); } settings.gfxData.TranslateTransform((int)textLocationPoint.X, (int)textLocationPoint.Y); settings.gfxData.RotateTransform((float)rotation); if (frame) { Rectangle stringRect = new Rectangle(0, 0, (int)stringSize.Width, (int)stringSize.Height); settings.gfxData.FillRectangle(frameBrush, stringRect); } settings.gfxData.DrawString(text, font, brush, new PointF(0, 0)); settings.gfxData.ResetTransform(); }
public static Bitmap DesignerModeBitmap(Size size, bool drawArrows = false) { Bitmap bmp = new Bitmap(size.Width, size.Height); Graphics gfx = Graphics.FromImage(bmp); gfx.Clear(ColorTranslator.FromHtml("#003366")); Brush brushLogo = new SolidBrush(ColorTranslator.FromHtml("#FFFFFF")); Brush brushMeasurements = new SolidBrush(ColorTranslator.FromHtml("#006699")); Pen pen = new Pen(ColorTranslator.FromHtml("#006699"), 3); pen.StartCap = System.Drawing.Drawing2D.LineCap.Round; pen.EndCap = System.Drawing.Drawing2D.LineCap.Round; float arrowSize = 7; float padding = 3; // logo FontFamily ff = new FontFamily(Fonts.GetDefaultFontName()); gfx.DrawString("ScottPlot", new Font(ff, 24, FontStyle.Bold), brushLogo, 10, 10); var titleSize = GDI.MeasureString(gfx, "ScottPlot", new Font(ff, 24, FontStyle.Bold)); gfx.DrawString($"version {GetVersionString()}", new Font(ff, 12, FontStyle.Italic), brushLogo, 12, (int)(10 + titleSize.Height * .7)); if (drawArrows) { // horizontal arrow PointF left = new PointF(padding, size.Height / 2); PointF leftA = new PointF(left.X + arrowSize, left.Y + arrowSize); PointF leftB = new PointF(left.X + arrowSize, left.Y - arrowSize); PointF right = new PointF(size.Width - padding, size.Height / 2); PointF rightA = new PointF(right.X - arrowSize, right.Y + arrowSize); PointF rightB = new PointF(right.X - arrowSize, right.Y - arrowSize); gfx.DrawLine(pen, left, right); gfx.DrawLine(pen, left, leftA); gfx.DrawLine(pen, left, leftB); gfx.DrawLine(pen, right, rightA); gfx.DrawLine(pen, right, rightB); gfx.DrawString($"{size.Width}px", new Font(ff, 12, FontStyle.Bold), brushMeasurements, (float)(size.Width * .2), (float)(size.Height * .5)); // vertical arrow PointF top = new PointF(size.Width / 2, padding); PointF topA = new PointF(top.X - arrowSize, top.Y + arrowSize); PointF topB = new PointF(top.X + arrowSize, top.Y + arrowSize); PointF bot = new PointF(size.Width / 2, size.Height - padding); PointF botA = new PointF(bot.X - arrowSize, bot.Y - arrowSize); PointF botB = new PointF(bot.X + arrowSize, bot.Y - arrowSize); gfx.DrawLine(pen, top, bot); gfx.DrawLine(pen, bot, botA); gfx.DrawLine(pen, bot, botB); gfx.DrawLine(pen, top, topA); gfx.DrawLine(pen, top, topB); gfx.RotateTransform(-90); gfx.DrawString($"{size.Height}px", new Font(ff, 12, FontStyle.Bold), brushMeasurements, (float)(-size.Height * .4), (float)(size.Width * .5)); } return(bmp); }
private void RecalculatePositionsAutomaticNumeric(Settings settings) { // predict maxLabelSize up front using predetermined label sizes string longestLabel = (dateFormat) ? "2019-08-20\n20:42:17" : "-8888"; maxLabelSize = GDI.MeasureString(settings.gfxData, longestLabel, settings.ticks.font); double low, high, tickSpacing; int maxTickCount; if (verticalAxis) { low = settings.axes.y.Min - settings.yAxisUnitsPerPixel; // add an extra pixel to capture the edge tick high = settings.axes.y.Max + settings.yAxisUnitsPerPixel; // add an extra pixel to capture the edge tick maxTickCount = (int)(settings.dataSize.Height / maxLabelSize.Height); tickSpacing = (settings.ticks.manualSpacingY != 0) ? settings.ticks.manualSpacingY : GetIdealTickSpacing(low, high, maxTickCount); } else { low = settings.axes.x.Min - settings.xAxisUnitsPerPixel; // add an extra pixel to capture the edge tick high = settings.axes.x.Max + settings.xAxisUnitsPerPixel; // add an extra pixel to capture the edge tick maxTickCount = (int)(settings.dataSize.Width / maxLabelSize.Width * 1.2); tickSpacing = (settings.ticks.manualSpacingX != 0) ? settings.ticks.manualSpacingX : GetIdealTickSpacing(low, high, maxTickCount); } // now that tick spacing is known, populate the list of ticks and labels double firstTickOffset = low % (double)tickSpacing; List <double> positions = new List <double>(); for (double position = low - firstTickOffset; position < high; position += (double)tickSpacing) { if ((low < position) && (high > position)) { positions.Add(position); } if (positions.Count > 999) { break; } } tickPositionsMajor = positions.ToArray(); if (dateFormat) { tickLabels = GetDateLabels(tickPositionsMajor, settings.culture); tickPositionsMinor = null; } else { (tickLabels, cornerLabel) = GetPrettyTickLabels( tickPositionsMajor, settings.ticks.useMultiplierNotation, settings.ticks.useOffsetNotation, settings.ticks.useExponentialNotation, invertSign: invertSign, culture: settings.culture ); if (logScale) { tickPositionsMinor = MinorFromMajorLog(tickPositionsMajor, low, high); } else { tickPositionsMinor = MinorFromMajor(tickPositionsMajor, 5, low, high); } } // now set the maximum label size based on the actual labels created maxLabelSize = LargestLabel(settings, tickLabels); }