internal void DrawMarker(SvgMarker svgMarker, SvgVisualElement pOwner, SKPoint pRefPoint, SKPoint pMarkerPoint1, SKPoint pMarkerPoint2, SKPoint pMarkerPoint3) { float xDiff = pMarkerPoint2.X - pMarkerPoint1.X; float yDiff = pMarkerPoint2.Y - pMarkerPoint1.Y; float fAngle1 = (float)(Math.Atan2(yDiff, xDiff) * 180.0 / Math.PI); xDiff = pMarkerPoint3.X - pMarkerPoint2.X; yDiff = pMarkerPoint3.Y - pMarkerPoint2.Y; float fAngle2 = (float)(Math.Atan2(yDiff, xDiff) * 180.0 / Math.PI); DrawMarker(svgMarker, pOwner, pRefPoint, (fAngle1 + fAngle2) / 2); }
internal SvgVisualElement?GetMarkerElement(SvgMarker svgMarker) { SvgVisualElement?markerElement = null; foreach (var child in svgMarker.Children) { if (child is SvgVisualElement svgVisualElement) { markerElement = svgVisualElement; break; } } return(markerElement); }
internal void DrawMarker(SvgMarker svgMarker, SvgVisualElement pOwner, SKPoint pRefPoint, SKPoint pMarkerPoint1, SKPoint pMarkerPoint2, bool isStartMarker) { float fAngle1 = 0f; if (svgMarker.Orient.IsAuto) { float xDiff = pMarkerPoint2.X - pMarkerPoint1.X; float yDiff = pMarkerPoint2.Y - pMarkerPoint1.Y; fAngle1 = (float)(Math.Atan2(yDiff, xDiff) * 180.0 / Math.PI); if (isStartMarker && svgMarker.Orient.IsAutoStartReverse) { fAngle1 += 180; } } DrawMarker(svgMarker, pOwner, pRefPoint, fAngle1); }
void CreateArrowEnd() { SvgMarker arrowEnd = this.doc.AddMarker(); arrowEnd.RefX = $"{this.ToPx(ArrowEndSize)}"; arrowEnd.RefY = $"{this.ToPx(ArrowEndSize / 2)}"; arrowEnd.MarkerWidth = $"{this.ToPx(ArrowEndSize)}"; arrowEnd.MarkerHeight = $"{this.ToPx(ArrowEndSize)}"; arrowEnd.MarkerUnits = "px"; arrowEnd.Id = ArrowEnd; SvgPolygon p = this.doc.AddPolygon(arrowEnd); p.Class = "connector"; p.Points = $"0 0 {this.ToPx(ArrowEndSize)} {this.ToPx(ArrowEndSize / 2)} 0 {this.ToPx(ArrowEndSize)}"; }
void CreateArrowEnd() { SvgMarker arrowEnd = this.doc.AddMarker(); arrowEnd.RefX = $"{this.ToPx(ArrowEndSize)}"; arrowEnd.RefY = $"{this.ToPx(ArrowEndSize / 2)}"; arrowEnd.MarkerWidth = $"{this.ToPx(ArrowEndSize)}"; arrowEnd.MarkerHeight = $"{this.ToPx(ArrowEndSize)}"; arrowEnd.MarkerUnits = "px"; arrowEnd.Id = ArrowEnd; SvgPolygon p = this.doc.AddPolygon(arrowEnd); p.Points = $"0 0 {this.ToPx(ArrowEndSize)} {this.ToPx(ArrowEndSize / 2)} 0 {this.ToPx(ArrowEndSize)}"; p.StrokeWidth = "0"; p.Fill = Color.Black; p.StrokeWidth = "0"; }
public static void CreateMarker(this SvgMarker svgMarker, SvgVisualElement pOwner, SKPoint pRefPoint, SKPoint pMarkerPoint1, SKPoint pMarkerPoint2, SKPoint pMarkerPoint3, SKRect skOwnerBounds, ref List <Drawable>?markerDrawables, CompositeDisposable disposable) { float xDiff = pMarkerPoint2.X - pMarkerPoint1.X; float yDiff = pMarkerPoint2.Y - pMarkerPoint1.Y; float fAngle1 = (float)(Math.Atan2(yDiff, xDiff) * 180.0 / Math.PI); xDiff = pMarkerPoint3.X - pMarkerPoint2.X; yDiff = pMarkerPoint3.Y - pMarkerPoint2.Y; float fAngle2 = (float)(Math.Atan2(yDiff, xDiff) * 180.0 / Math.PI); var markerDrawable = new MarkerDrawable(svgMarker, pOwner, pRefPoint, (fAngle1 + fAngle2) / 2, skOwnerBounds, null, null); if (markerDrawables == null) { markerDrawables = new List <Drawable>(); } markerDrawables.Add(markerDrawable); disposable.Add(markerDrawable); }
void CreateArrowStart() { float radius = 0.125f; SvgMarker arrowStart = this.doc.AddMarker(); arrowStart.RefX = $"{this.ToPx(radius)}"; arrowStart.RefY = $"{this.ToPx(radius)}"; arrowStart.MarkerWidth = $"{this.ToPx(2 * radius)}"; arrowStart.MarkerHeight = $"{this.ToPx(2 * radius)}"; arrowStart.MarkerUnits = "px"; arrowStart.Id = ArrowStart; SvgCircle c = this.doc.AddCircle(arrowStart); c.Class = "connector"; c.CX = $"{this.ToPx(radius)}"; c.CY = $"{this.ToPx(radius)}"; c.R = $"{this.ToPx(radius)}"; }
void CreateArrowStart() { float radius = 0.125f; SvgMarker arrowStart = this.doc.AddMarker(); arrowStart.RefX = $"{this.ToPx(radius)}"; arrowStart.RefY = $"{this.ToPx(radius)}"; arrowStart.MarkerWidth = $"{this.ToPx(2 * radius)}"; arrowStart.MarkerHeight = $"{this.ToPx(2 * radius)}"; arrowStart.MarkerUnits = "px"; arrowStart.Id = ArrowStart; SvgCircle c = this.doc.AddCircle(arrowStart); c.CX = $"{this.ToPx(radius)}"; c.CY = $"{this.ToPx(radius)}"; c.R = $"{this.ToPx(radius)}"; c.Fill = Color.Black; c.StrokeWidth = "0"; }
public static void CreateMarker(this SvgMarker svgMarker, SvgVisualElement pOwner, SKPoint pRefPoint, SKPoint pMarkerPoint1, SKPoint pMarkerPoint2, bool isStartMarker, SKRect skOwnerBounds, ref List <Drawable>?markerDrawables, CompositeDisposable disposable, Attributes ignoreAttributes = Attributes.None) { float fAngle1 = 0f; if (svgMarker.Orient.IsAuto) { float xDiff = pMarkerPoint2.X - pMarkerPoint1.X; float yDiff = pMarkerPoint2.Y - pMarkerPoint1.Y; fAngle1 = (float)(Math.Atan2(yDiff, xDiff) * 180.0 / Math.PI); if (isStartMarker && svgMarker.Orient.IsAutoStartReverse) { fAngle1 += 180; } } var markerDrawable = new MarkerDrawable(svgMarker, pOwner, pRefPoint, fAngle1, skOwnerBounds, null, null, ignoreAttributes); if (markerDrawables == null) { markerDrawables = new List <Drawable>(); } markerDrawables.Add(markerDrawable); disposable.Add(markerDrawable); }
public static MarkerDrawable Create(SvgMarker svgMarker, SvgVisualElement pOwner, Point pMarkerPoint, float fAngle, Rect skOwnerBounds, DrawableBase?parent, IAssetLoader assetLoader, Attributes ignoreAttributes = Attributes.None) { var drawable = new MarkerDrawable(assetLoader) { Element = svgMarker, Parent = parent, IgnoreAttributes = Attributes.Display | ignoreAttributes, IsDrawable = true }; if (!drawable.IsDrawable) { return(drawable); } var markerElement = drawable.GetMarkerElement(svgMarker); if (markerElement is null) { drawable.IsDrawable = false; return(drawable); } var skMarkerMatrix = Matrix.CreateIdentity(); var skMatrixMarkerPoint = Matrix.CreateTranslation(pMarkerPoint.X, pMarkerPoint.Y); skMarkerMatrix = skMarkerMatrix.PreConcat(skMatrixMarkerPoint); var skMatrixAngle = Matrix.CreateRotationDegrees(svgMarker.Orient.IsAuto ? fAngle : svgMarker.Orient.Angle); skMarkerMatrix = skMarkerMatrix.PreConcat(skMatrixAngle); var strokeWidth = pOwner.StrokeWidth.ToDeviceValue(UnitRenderingType.Other, svgMarker, skOwnerBounds); var refX = svgMarker.RefX.ToDeviceValue(UnitRenderingType.Horizontal, svgMarker, skOwnerBounds); var refY = svgMarker.RefY.ToDeviceValue(UnitRenderingType.Vertical, svgMarker, skOwnerBounds); var markerWidth = svgMarker.MarkerWidth.ToDeviceValue(UnitRenderingType.Other, svgMarker, skOwnerBounds); var markerHeight = svgMarker.MarkerHeight.ToDeviceValue(UnitRenderingType.Other, svgMarker, skOwnerBounds); var viewBoxToMarkerUnitsScaleX = 1f; var viewBoxToMarkerUnitsScaleY = 1f; switch (svgMarker.MarkerUnits) { case SvgMarkerUnits.StrokeWidth: { var skMatrixStrokeWidth = Matrix.CreateScale(strokeWidth, strokeWidth); skMarkerMatrix = skMarkerMatrix.PreConcat(skMatrixStrokeWidth); var viewBoxWidth = svgMarker.ViewBox.Width; var viewBoxHeight = svgMarker.ViewBox.Height; var scaleFactorWidth = viewBoxWidth <= 0 ? 1 : markerWidth / viewBoxWidth; var scaleFactorHeight = viewBoxHeight <= 0 ? 1 : markerHeight / viewBoxHeight; viewBoxToMarkerUnitsScaleX = Math.Min(scaleFactorWidth, scaleFactorHeight); viewBoxToMarkerUnitsScaleY = Math.Min(scaleFactorWidth, scaleFactorHeight); var skMatrixTranslateRefXY = Matrix.CreateTranslation(-refX * viewBoxToMarkerUnitsScaleX, -refY * viewBoxToMarkerUnitsScaleY); skMarkerMatrix = skMarkerMatrix.PreConcat(skMatrixTranslateRefXY); var skMatrixScaleXY = Matrix.CreateScale(viewBoxToMarkerUnitsScaleX, viewBoxToMarkerUnitsScaleY); skMarkerMatrix = skMarkerMatrix.PreConcat(skMatrixScaleXY); } break; case SvgMarkerUnits.UserSpaceOnUse: { var skMatrixTranslateRefXY = Matrix.CreateTranslation(-refX, -refY); skMarkerMatrix = skMarkerMatrix.PreConcat(skMatrixTranslateRefXY); } break; } switch (svgMarker.Overflow) { case SvgOverflow.Auto: case SvgOverflow.Visible: case SvgOverflow.Inherit: break; default: drawable.MarkerClipRect = Rect.Create( svgMarker.ViewBox.MinX, svgMarker.ViewBox.MinY, markerWidth / viewBoxToMarkerUnitsScaleX, markerHeight / viewBoxToMarkerUnitsScaleY); break; } var markerElementDrawable = DrawableFactory.Create(markerElement, skOwnerBounds, drawable, assetLoader, Attributes.Display); if (markerElementDrawable is { })
public void TestArrowCodeCreation() { // Sample code from Issue 212. Thanks to podostro. const int width = 50; const int height = 50; var document = new SvgDocument() { ID = "svgMap", ViewBox = new SvgViewBox(0, 0, width, height) }; var defsElement = new SvgDefinitionList() { ID = "defsMap" }; document.Children.Add(defsElement); var groupElement = new SvgGroup() { ID = "gMap" }; document.Children.Add(groupElement); var arrowPath = new SvgPath() { ID = "pathMarkerArrow", Fill = new SvgColourServer(Color.Black), PathData = SvgPathBuilder.Parse(@"M0,0 L4,2 L0,4 L1,2 z") }; var arrowMarker = new SvgMarker() { ID = "markerArrow", MarkerUnits = SvgMarkerUnits.StrokeWidth, MarkerWidth = 5, MarkerHeight = 5, RefX = 3, RefY = 2, Orient = new SvgOrient() { IsAuto = true }, Children = { arrowPath } }; defsElement.Children.Add(arrowMarker); var line = new SvgLine() { ID = "lineLinkedPoint", StartX = 0, StartY = 15, EndX = 35, EndY = 35, Stroke = new SvgColourServer(Color.Black), StrokeWidth = 3, MarkerEnd = new Uri(string.Format("url(#{0})", arrowMarker.ID), UriKind.Relative) }; groupElement.Children.Add(line); var svgXml = document.GetXML(); var img = document.Draw(); var file = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); File.WriteAllText(file + ".svg", svgXml); img.Save(file + ".png"); Debug.WriteLine(string.Format("Svg saved to '{0}'", file)); Debugger.Break(); // Remove var svg = new FileInfo(file + ".svg"); if (svg.Exists) { svg.Delete(); } var png = new FileInfo(file + ".png"); if (png.Exists) { png.Delete(); } }
public MarkerDrawable(SvgMarker svgMarker, SvgVisualElement pOwner, SKPoint pMarkerPoint, float fAngle, SKRect skOwnerBounds, Drawable?root, Drawable?parent, Attributes ignoreAttributes = Attributes.None) : base(svgMarker, root, parent) { IgnoreAttributes = Attributes.Display | ignoreAttributes; IsDrawable = true; if (!IsDrawable) { return; } var markerElement = GetMarkerElement(svgMarker); if (markerElement == null) { IsDrawable = false; return; } var skMarkerMatrix = SKMatrix.MakeIdentity(); var skMatrixMarkerPoint = SKMatrix.MakeTranslation(pMarkerPoint.X, pMarkerPoint.Y); skMarkerMatrix = skMarkerMatrix.PreConcat(skMatrixMarkerPoint); var skMatrixAngle = SKMatrix.MakeRotationDegrees(svgMarker.Orient.IsAuto ? fAngle : svgMarker.Orient.Angle); skMarkerMatrix = skMarkerMatrix.PreConcat(skMatrixAngle); var strokeWidth = pOwner.StrokeWidth.ToDeviceValue(UnitRenderingType.Other, svgMarker, skOwnerBounds); var refX = svgMarker.RefX.ToDeviceValue(UnitRenderingType.Horizontal, svgMarker, skOwnerBounds); var refY = svgMarker.RefY.ToDeviceValue(UnitRenderingType.Vertical, svgMarker, skOwnerBounds); float markerWidth = svgMarker.MarkerWidth.ToDeviceValue(UnitRenderingType.Other, svgMarker, skOwnerBounds); float markerHeight = svgMarker.MarkerHeight.ToDeviceValue(UnitRenderingType.Other, svgMarker, skOwnerBounds); float viewBoxToMarkerUnitsScaleX = 1f; float viewBoxToMarkerUnitsScaleY = 1f; switch (svgMarker.MarkerUnits) { case SvgMarkerUnits.StrokeWidth: { var skMatrixStrokeWidth = SKMatrix.MakeScale(strokeWidth, strokeWidth); skMarkerMatrix = skMarkerMatrix.PreConcat(skMatrixStrokeWidth); var viewBoxWidth = svgMarker.ViewBox.Width; var viewBoxHeight = svgMarker.ViewBox.Height; var scaleFactorWidth = (viewBoxWidth <= 0) ? 1 : (markerWidth / viewBoxWidth); var scaleFactorHeight = (viewBoxHeight <= 0) ? 1 : (markerHeight / viewBoxHeight); viewBoxToMarkerUnitsScaleX = Math.Min(scaleFactorWidth, scaleFactorHeight); viewBoxToMarkerUnitsScaleY = Math.Min(scaleFactorWidth, scaleFactorHeight); var skMatrixTranslateRefXY = SKMatrix.MakeTranslation(-refX * viewBoxToMarkerUnitsScaleX, -refY * viewBoxToMarkerUnitsScaleY); skMarkerMatrix = skMarkerMatrix.PreConcat(skMatrixTranslateRefXY); var skMatrixScaleXY = SKMatrix.MakeScale(viewBoxToMarkerUnitsScaleX, viewBoxToMarkerUnitsScaleY); skMarkerMatrix = skMarkerMatrix.PreConcat(skMatrixScaleXY); } break; case SvgMarkerUnits.UserSpaceOnUse: { var skMatrixTranslateRefXY = SKMatrix.MakeTranslation(-refX, -refY); skMarkerMatrix = skMarkerMatrix.PreConcat(skMatrixTranslateRefXY); } break; } switch (svgMarker.Overflow) { case SvgOverflow.Auto: case SvgOverflow.Visible: case SvgOverflow.Inherit: break; default: MarkerClipRect = SKRect.Create( svgMarker.ViewBox.MinX, svgMarker.ViewBox.MinY, markerWidth / viewBoxToMarkerUnitsScaleX, markerHeight / viewBoxToMarkerUnitsScaleY); break; } var drawable = DrawableFactory.Create(markerElement, skOwnerBounds, root, this, Attributes.Display); if (drawable != null) { MarkerElementDrawable = drawable; _disposable.Add(MarkerElementDrawable); } else { IsDrawable = false; return; } IsAntialias = SvgPaintingExtensions.IsAntialias(svgMarker); TransformedBounds = MarkerElementDrawable.TransformedBounds; Transform = SvgTransformsExtensions.ToSKMatrix(svgMarker.Transforms); Transform = Transform.PreConcat(skMarkerMatrix); Fill = null; Stroke = null; // TODO: Transform _skBounds using _skMatrix. TransformedBounds = Transform.MapRect(TransformedBounds); }
public Marker(SvgMarker svgMarker) { matrix = SvgHelper.GetSKMatrix(svgMarker.Transforms); }
internal void DrawMarker(SvgMarker svgMarker, SvgVisualElement pOwner, SKPoint pMarkerPoint, float fAngle) { var markerElement = GetMarkerElement(svgMarker); if (markerElement == null) { return; } var skMarkerMatrix = SKMatrix.MakeIdentity(); var skMatrixMarkerPoint = SKMatrix.MakeTranslation(pMarkerPoint.X, pMarkerPoint.Y); SKMatrix.PreConcat(ref skMarkerMatrix, ref skMatrixMarkerPoint); var skMatrixAngle = SKMatrix.MakeRotationDegrees(svgMarker.Orient.IsAuto ? fAngle : svgMarker.Orient.Angle); SKMatrix.PreConcat(ref skMarkerMatrix, ref skMatrixAngle); var strokeWidth = pOwner.StrokeWidth.ToDeviceValue(null, UnitRenderingType.Other, svgMarker); var refX = svgMarker.RefX.ToDeviceValue(null, UnitRenderingType.Horizontal, svgMarker); var refY = svgMarker.RefY.ToDeviceValue(null, UnitRenderingType.Horizontal, svgMarker); float markerWidth = svgMarker.MarkerWidth; float markerHeight = svgMarker.MarkerHeight; float viewBoxToMarkerUnitsScaleX = 1f; float viewBoxToMarkerUnitsScaleY = 1f; switch (svgMarker.MarkerUnits) { case SvgMarkerUnits.StrokeWidth: { var skMatrixStrokeWidth = SKMatrix.MakeScale(strokeWidth, strokeWidth); SKMatrix.PreConcat(ref skMarkerMatrix, ref skMatrixStrokeWidth); var viewBoxWidth = svgMarker.ViewBox.Width; var viewBoxHeight = svgMarker.ViewBox.Height; var scaleFactorWidth = (viewBoxWidth <= 0) ? 1 : (markerWidth / viewBoxWidth); var scaleFactorHeight = (viewBoxHeight <= 0) ? 1 : (markerHeight / viewBoxHeight); viewBoxToMarkerUnitsScaleX = Math.Min(scaleFactorWidth, scaleFactorHeight); viewBoxToMarkerUnitsScaleY = Math.Min(scaleFactorWidth, scaleFactorHeight); var skMatrixTranslateRefXY = SKMatrix.MakeTranslation(-refX * viewBoxToMarkerUnitsScaleX, -refY * viewBoxToMarkerUnitsScaleY); SKMatrix.PreConcat(ref skMarkerMatrix, ref skMatrixTranslateRefXY); var skMatrixScaleXY = SKMatrix.MakeScale(viewBoxToMarkerUnitsScaleX, viewBoxToMarkerUnitsScaleY); SKMatrix.PreConcat(ref skMarkerMatrix, ref skMatrixScaleXY); } break; case SvgMarkerUnits.UserSpaceOnUse: { var skMatrixTranslateRefXY = SKMatrix.MakeTranslation(-refX, -refY); SKMatrix.PreConcat(ref skMarkerMatrix, ref skMatrixTranslateRefXY); } break; } _skCanvas.Save(); var skMatrix = SkiaUtil.GetSKMatrix(svgMarker.Transforms); SKMatrix.PreConcat(ref skMatrix, ref skMarkerMatrix); SetTransform(skMatrix); SetClipPath(svgMarker, _disposable); var skPaintOpacity = SetOpacity(svgMarker, _disposable); var skPaintFilter = SetFilter(svgMarker, _disposable); switch (svgMarker.Overflow) { case SvgOverflow.Auto: case SvgOverflow.Visible: case SvgOverflow.Inherit: break; default: var skClipRect = SKRect.Create( svgMarker.ViewBox.MinX, svgMarker.ViewBox.MinY, markerWidth / viewBoxToMarkerUnitsScaleX, markerHeight / viewBoxToMarkerUnitsScaleY); _skCanvas.ClipRect(skClipRect, SKClipOperation.Intersect); break; } Draw(markerElement, true); if (skPaintFilter != null) { _skCanvas.Restore(); } if (skPaintOpacity != null) { _skCanvas.Restore(); } _skCanvas.Restore(); }
public static void MakeSVG(List <CapturePacket> packets, string fileName) { const int baselinestep = 250; // distance between vertical lines const int horizontalBase = 130; // upper range for the vertical lines const int unitBoxWidth = 120; // width of device box const int unitBoxHeight = 40; // height of device box const int firstarrowdistance = 50; // vertical distance before the first sequence arrow const int maxboxwidth = 1000; // maximum width of description textboxes var font = new Font("Calibri", 9); // SVG and C# have different ideas of what a fontsize is apparently, so we set this lower and hope for the best int baselinegen = -100; // iterator for making the vertical lines, the first line does one step from this value int arrowgen = horizontalBase + firstarrowdistance; // iterator for making sequence arrows // iterate through the data and gather what we need into a little struct for convenience List <Sequence> list = GetSequences(packets, baselinestep, out var devices, ref baselinegen); // after all vertical lines have been placed, make one for the description boxes int descriptionBaseline = baselinegen + 50; var svg = new SvgDocument(); var groupDevices = new SvgGroup { FontFamily = "Calibri", FontSize = 16 }; var groupArrows = new SvgGroup { ID = "arrows", Stroke = new SvgColourServer(Color.Black), StrokeWidth = 2 }; var groupArrowTexts = new SvgGroup { ID = "arrowtexts", FontFamily = "Calibri", FontSize = 11 }; var groupBaselines = new SvgGroup { ID = "baselines", Stroke = new SvgColourServer(Color.Black), StrokeWidth = 2, StrokeDashArray = new SvgUnitCollection { 10, 10 } }; var groupDescriptionBoxes = new SvgGroup { ID = "descriptionboxes", Fill = new SvgColourServer(Color.Transparent), Stroke = new SvgColourServer(Color.Black), StrokeWidth = 2 }; var groupDescriptionTexts = new SvgGroup { ID = "descriptiontexts", FontFamily = "Calibri", FontSize = 12 }; svg.Children.Add(groupDevices); svg.Children.Add(groupArrows); svg.Children.Add(groupArrowTexts); svg.Children.Add(groupBaselines); svg.Children.Add(groupDescriptionBoxes); svg.Children.Add(groupDescriptionTexts); var svgDefinitionList = new SvgDefinitionList(); var svgMarker = new SvgMarker { ID = "arrow", MarkerWidth = 10, MarkerHeight = 10, RefX = 9, RefY = 3, Orient = new SvgOrient { IsAuto = true }, MarkerUnits = SvgMarkerUnits.StrokeWidth }; var svgPath = new SvgPath { PathData = new SvgPathSegmentList { new SvgMoveToSegment(new PointF(0, 0)), new SvgLineSegment(new PointF(0, 0), new PointF(0, 6)), new SvgLineSegment(new PointF(0, 0), new PointF(9, 3)), new SvgClosePathSegment() }, Fill = new SvgColourServer(Color.Black) }; svgMarker.Children.Add(svgPath); svgDefinitionList.Children.Add(svgMarker); svg.Children.Add(svgDefinitionList); // make the device boxes foreach (KeyValuePair <IPAddress, int> device in devices) { groupDevices.Children.Add(new SvgRectangle { Fill = new SvgColourServer(Color.White), Stroke = new SvgColourServer(Color.Black), StrokeWidth = 2, X = device.Value - unitBoxWidth / 2, Y = horizontalBase - unitBoxHeight, Width = unitBoxWidth, Height = unitBoxHeight }); groupDevices.Children.Add(new SvgText { Text = device.Key.ToString(), Stroke = new SvgColourServer(Color.Black), X = new SvgUnitCollection { new SvgUnit(device.Value) }, Y = new SvgUnitCollection { new SvgUnit(horizontalBase - unitBoxHeight / 2) }, TextAnchor = SvgTextAnchor.Middle }); } foreach (Sequence sequence in list) { // get the x axis of the two devices we are relating int one = devices[sequence.From]; int two = devices[sequence.To]; groupArrows.Children.Add(new SvgLine { StartX = one, StartY = arrowgen, EndX = two, EndY = arrowgen, MarkerEnd = new Uri("url(#arrow)", UriKind.Relative) }); // get middle of arrow int right = Math.Max(one, two); int left = Math.Min(one, two); int middle = (right - left) / 2; middle = left + middle; groupArrowTexts.Children.Add(new SvgText { Text = sequence.Name, X = new SvgUnitCollection { new SvgUnit(middle) }, Y = new SvgUnitCollection { new SvgUnit(arrowgen - 2) }, TextAnchor = SvgTextAnchor.Middle }); var svgBoxText = new SvgText { X = new SvgUnitCollection { new SvgUnit(descriptionBaseline + 5) }, Y = new SvgUnitCollection { new SvgUnit(arrowgen - 12) } }; svgBoxText.Children.Add(new SvgTextSpan { Text = sequence.Time, TextDecoration = SvgTextDecoration.Underline, X = new SvgUnitCollection { new SvgUnit(descriptionBaseline + 5) }, Dy = new SvgUnitCollection { new SvgUnit(SvgUnitType.Em, 1.2f) } }); int maxstrlen = TextRenderer.MeasureText(sequence.Time, font).Width; var lines = 1; foreach (KeyValuePair <string, string> pair in sequence.Dic) { var both = new SvgTextSpan { X = new SvgUnitCollection { new SvgUnit(descriptionBaseline + 5) }, Dy = new SvgUnitCollection { new SvgUnit(SvgUnitType.Em, 1.2f) } }; string textKey = pair.Key + ": "; string textValue = Functions.RemoveInvalidXMLChars(pair.Value); int strlen = TextRenderer.MeasureText(textKey + textValue, font).Width; if (strlen > maxboxwidth) { // ooof string tv1 = textValue; var tv2 = ""; while (TextRenderer.MeasureText(textKey + tv1, font).Width > maxboxwidth) { tv2 = tv1[tv1.Length - 1] + tv2; tv1 = tv1.Substring(0, tv1.Length - 1); } var keySpan = new SvgTextSpan { Text = textKey, FontWeight = SvgFontWeight.Bold }; var valueSpan1 = new SvgTextSpan { Text = tv1 }; var valueSpan2 = new SvgTextSpan { Text = tv2, X = new SvgUnitCollection { new SvgUnit(descriptionBaseline + 5) }, Dy = new SvgUnitCollection { new SvgUnit(SvgUnitType.Em, 1.2f) } }; both.Children.Add(keySpan); both.Children.Add(valueSpan1); svgBoxText.Children.Add(both); svgBoxText.Children.Add(valueSpan2); lines += 2; } else { var keySpan = new SvgTextSpan { Text = textKey, FontWeight = SvgFontWeight.Bold }; var valueSpan = new SvgTextSpan { Text = textValue }; both.Children.Add(keySpan); both.Children.Add(valueSpan); svgBoxText.Children.Add(both); lines++; } if (strlen > maxstrlen) { maxstrlen = strlen; } } // box height calc, 30 margin + 14 per line. Then have 20 between box bottom and next arrow (at least) var boxheight = (int)(lines * font.Height * 1.02); // draw the box groupDescriptionBoxes.Children.Add(new SvgRectangle { X = descriptionBaseline, Y = arrowgen - 10, Width = maxstrlen, Height = boxheight }); // add text after box groupDescriptionTexts.Children.Add(svgBoxText); // setup next arrow arrowgen += boxheight + 30; } // finally, draw the baselines foreach (KeyValuePair <IPAddress, int> device in devices) { groupBaselines.Children.Add(new SvgLine { StartX = device.Value, StartY = horizontalBase, EndX = device.Value, EndY = arrowgen }); } // now lets make SVG!!! svg.Width = descriptionBaseline + maxboxwidth + 5; svg.Height = arrowgen + 5; svg.ViewBox = new SvgViewBox(0, 0, descriptionBaseline + maxboxwidth + 5, arrowgen + 5); using (FileStream fileStream = File.Create(fileName)) { svg.Write(fileStream); } }
public void TestArrowCodeCreation() { // Sample code from Issue 212. Thanks to podostro. const int width = 50; const int height = 50; var document = new SvgDocument() { ID = "svgMap", ViewBox = new SvgViewBox(0, 0, width, height) }; var defsElement = new SvgDefinitionList() { ID = "defsMap" }; document.Children.Add(defsElement); var groupElement = new SvgGroup() { ID = "gMap" }; document.Children.Add(groupElement); var arrowPath = new SvgPath() { ID = "pathMarkerArrow", Fill = new SvgColourServer(Color.Black), PathData = SvgPathBuilder.Parse(@"M0,0 L4,2 L0,4 L1,2 z") }; var arrowMarker = new SvgMarker() { ID = "markerArrow", MarkerUnits = SvgMarkerUnits.StrokeWidth, MarkerWidth = 5, MarkerHeight = 5, RefX = 3, RefY = 2, Orient = new SvgOrient() { IsAuto = true }, Children = { arrowPath } }; defsElement.Children.Add(arrowMarker); var line = new SvgLine() { ID = "lineLinkedPoint", StartX = 0, StartY = 15, EndX = 35, EndY = 35, Stroke = new SvgColourServer(Color.Black), StrokeWidth = 3, MarkerEnd = new Uri(string.Format("url(#{0})", arrowMarker.ID), UriKind.Relative) }; groupElement.Children.Add(line); var svgXml = document.GetXML(); var img = document.Draw(); var file = Path.Combine(Path.GetTempPath(), Guid.NewGuid().ToString()); File.WriteAllText(file + ".svg", svgXml); img.Save(file + ".png"); Debug.WriteLine(string.Format("Svg saved to '{0}'", file)); Debugger.Break(); // Remove var svg = new FileInfo(file + ".svg"); if (svg.Exists) svg.Delete(); var png = new FileInfo(file + ".png"); if (png.Exists) png.Delete(); }