From bfa6af9f9b1b473dd7f77a5a4bed5db53d4108fe Mon Sep 17 00:00:00 2001 From: florian Date: Fri, 8 Mar 2024 11:54:00 +0100 Subject: [PATCH] add functionality to zoom to a specified shape --- BlazorSvgEditor.SvgEditor/Shapes/Circle.cs | 2 +- BlazorSvgEditor.SvgEditor/Shapes/Polygon.cs | 2 +- BlazorSvgEditor.SvgEditor/Shapes/Rectangle.cs | 2 +- BlazorSvgEditor.SvgEditor/Shapes/Shape.cs | 2 +- .../SvgEditor.PublicMethods.cs | 57 +++++++++++++++++++ .../SvgEditor.Transformations.cs | 29 ++++++++++ BlazorSvgEditor.SvgEditor/SvgEditor.razor | 2 +- BlazorSvgEditor.WasmTest/Pages/Preview.razor | 8 +-- .../Pages/Preview.razor.cs | 9 +-- 9 files changed, 100 insertions(+), 13 deletions(-) diff --git a/BlazorSvgEditor.SvgEditor/Shapes/Circle.cs b/BlazorSvgEditor.SvgEditor/Shapes/Circle.cs index 7f91384..dedb76d 100644 --- a/BlazorSvgEditor.SvgEditor/Shapes/Circle.cs +++ b/BlazorSvgEditor.SvgEditor/Shapes/Circle.cs @@ -18,7 +18,7 @@ public Circle(SvgEditor svgEditor) : base(svgEditor) { } public double Cy { get; set; } public double R { get; set; } - protected override BoundingBox Bounds => new BoundingBox(Cx -R, Cy - R, Cx + R, Cy + R); + public override BoundingBox Bounds => new BoundingBox(Cx -R, Cy - R, Cx + R, Cy + R); internal override void SnapToInteger() { diff --git a/BlazorSvgEditor.SvgEditor/Shapes/Polygon.cs b/BlazorSvgEditor.SvgEditor/Shapes/Polygon.cs index d9141bb..6697b1c 100644 --- a/BlazorSvgEditor.SvgEditor/Shapes/Polygon.cs +++ b/BlazorSvgEditor.SvgEditor/Shapes/Polygon.cs @@ -124,7 +124,7 @@ internal override async Task HandlePointerUp(PointerEventArgs eventArgs) } - protected override BoundingBox Bounds => new() + public override BoundingBox Bounds => new() { Left = Points.OrderBy(x => x.X).FirstOrDefault().X, Right = Points.OrderByDescending(x => x.X).FirstOrDefault().X, diff --git a/BlazorSvgEditor.SvgEditor/Shapes/Rectangle.cs b/BlazorSvgEditor.SvgEditor/Shapes/Rectangle.cs index df671ec..6dff50e 100644 --- a/BlazorSvgEditor.SvgEditor/Shapes/Rectangle.cs +++ b/BlazorSvgEditor.SvgEditor/Shapes/Rectangle.cs @@ -19,7 +19,7 @@ public Rectangle(SvgEditor svgEditor) : base(svgEditor){ } private Coord AddPosition = new(-1, -1); - protected override BoundingBox Bounds => new BoundingBox(X, Y, X + Width, Y + Height); + public override BoundingBox Bounds => new BoundingBox(X, Y, X + Width, Y + Height); internal override void SnapToInteger() { diff --git a/BlazorSvgEditor.SvgEditor/Shapes/Shape.cs b/BlazorSvgEditor.SvgEditor/Shapes/Shape.cs index cb2da1b..ab3102e 100644 --- a/BlazorSvgEditor.SvgEditor/Shapes/Shape.cs +++ b/BlazorSvgEditor.SvgEditor/Shapes/Shape.cs @@ -90,7 +90,7 @@ internal void UnHoverShape() FillOpacity = 1; } - protected abstract BoundingBox Bounds { get; } + public abstract BoundingBox Bounds { get; } internal abstract void SnapToInteger(); internal abstract void HandlePointerMove(PointerEventArgs eventArgs); diff --git a/BlazorSvgEditor.SvgEditor/SvgEditor.PublicMethods.cs b/BlazorSvgEditor.SvgEditor/SvgEditor.PublicMethods.cs index 45f10aa..2948ab3 100644 --- a/BlazorSvgEditor.SvgEditor/SvgEditor.PublicMethods.cs +++ b/BlazorSvgEditor.SvgEditor/SvgEditor.PublicMethods.cs @@ -67,6 +67,63 @@ public async Task ResetTransform() await SetContainerBoundingBox(); await ResetTransformation(); } + + + public async Task ZoomToShape(int shapeId, double marginPercentage) + { + Shape? shape = Shapes.FirstOrDefault(s => s.CustomId == shapeId); + if (shape != null) + { + await SetContainerBoundingBox(); + + var shapeWidth = shape.Bounds.Right - shape.Bounds.Left; + var shapeHeight = shape.Bounds.Bottom - shape.Bounds.Top; + var marginPixels = Math.Max(shapeWidth, shapeHeight) * marginPercentage; + + //Die BoundingBox des elements ist im Verhältnis breiter als die des Containers + var shapeBoundingBoxWithMargin = new BoundingBox + { + Left = shape.Bounds.Left - marginPixels, + Right = shape.Bounds.Right + marginPixels, + Top = shape.Bounds.Top - marginPixels, + Bottom = shape.Bounds.Bottom + marginPixels + }; + + ZoomToShape(shapeBoundingBoxWithMargin); + } + } + + public async Task ZoomToShape(int shapeId, int marginPixels) + { + Shape? shape = Shapes.FirstOrDefault(s => s.CustomId == shapeId); + if (shape != null) + { + await SetContainerBoundingBox(); + + var shapeWidth = shape.Bounds.Right - shape.Bounds.Left; + var shapeHeight = shape.Bounds.Bottom - shape.Bounds.Top; + bool isShapeWiderThanContainer = (shapeWidth / shapeHeight) > (_containerBoundingBox.Width / _containerBoundingBox.Height); + + var scaleForCalculatingMargin = isShapeWiderThanContainer ? (double)_containerBoundingBox.Width / shapeWidth : (double)_containerBoundingBox.Height / shapeHeight; + + //Die BoundingBox des elements ist im Verhältnis breiter als die des Containers + var shapeBoundingBoxWithMargin = new BoundingBox + { + Left = shape.Bounds.Left - marginPixels / scaleForCalculatingMargin, + Right = shape.Bounds.Right + marginPixels / scaleForCalculatingMargin, + Top = shape.Bounds.Top - marginPixels / scaleForCalculatingMargin, + Bottom = shape.Bounds.Bottom + marginPixels / scaleForCalculatingMargin + }; + + ZoomToShape(shapeBoundingBoxWithMargin); + } + } + + public async Task ZoomToShape(int shapeId) + { + await ZoomToShape(shapeId, 0.05); + } + //Use this method to set the translation to a specific value -> e.g. to syncronize the translation of two SvgEditors public void SetTranslateAndScale(Coord? newTranslate = null, double? newScale = null) diff --git a/BlazorSvgEditor.SvgEditor/SvgEditor.Transformations.cs b/BlazorSvgEditor.SvgEditor/SvgEditor.Transformations.cs index 0d6019b..fec91db 100644 --- a/BlazorSvgEditor.SvgEditor/SvgEditor.Transformations.cs +++ b/BlazorSvgEditor.SvgEditor/SvgEditor.Transformations.cs @@ -1,4 +1,5 @@ using BlazorSvgEditor.SvgEditor.Helper; +using BlazorSvgEditor.SvgEditor.Misc; using Microsoft.AspNetCore.Components.Web; namespace BlazorSvgEditor.SvgEditor; @@ -90,6 +91,34 @@ private async Task ResetTransformation() await InvokeTranslationChanged(); } + private void ZoomToShape(BoundingBox shapeBoundingBox) + { + var newShapeWidth = shapeBoundingBox.Right - shapeBoundingBox.Left; + var newShapeHeight = shapeBoundingBox.Bottom - shapeBoundingBox.Top; + + bool isShapeWiderThanContainer = (newShapeWidth / newShapeHeight) > (_containerBoundingBox.Width / _containerBoundingBox.Height); + + if (isShapeWiderThanContainer) + { + Scale = (double)_containerBoundingBox.Width / newShapeWidth; + + var translateX = (shapeBoundingBox.Left * Scale * -1) + (_containerBoundingBox.Width - newShapeWidth * Scale) / 2; + var translateY = (shapeBoundingBox.Top * Scale * -1) + (_containerBoundingBox.Height - newShapeHeight * Scale) / 2; + + Translate = new (translateX, translateY); + } + else + { + Scale = (double)_containerBoundingBox.Height / newShapeHeight; + + var translateX = (shapeBoundingBox.Left * Scale * -1) + (_containerBoundingBox.Width - newShapeWidth * Scale) / 2; + var translateY = (shapeBoundingBox.Top * Scale * -1) + (_containerBoundingBox.Height - newShapeHeight * Scale) / 2; + + Translate = new (translateX, translateY); + } + } + + internal double GetScaledValue(double value, int decimals = 1) => (value *(1/ Scale )).Round(decimals); diff --git a/BlazorSvgEditor.SvgEditor/SvgEditor.razor b/BlazorSvgEditor.SvgEditor/SvgEditor.razor index fabb51d..7db264b 100644 --- a/BlazorSvgEditor.SvgEditor/SvgEditor.razor +++ b/BlazorSvgEditor.SvgEditor/SvgEditor.razor @@ -57,7 +57,7 @@ ContainerBox: X: @(Math.Round(_containerBoundingBox.Width, 1))px Y: @(Math.Round(_containerBoundingBox.Height, 1))px - + @foreach(var shape in Shapes) { @shape.ToString() diff --git a/BlazorSvgEditor.WasmTest/Pages/Preview.razor b/BlazorSvgEditor.WasmTest/Pages/Preview.razor index 6e79246..2a1f597 100644 --- a/BlazorSvgEditor.WasmTest/Pages/Preview.razor +++ b/BlazorSvgEditor.WasmTest/Pages/Preview.razor @@ -14,9 +14,8 @@
+ OnShapeChanged="EditorShapeChanged" ImageSourceLoadingFunc="GetImageSource" ShowDiagnosticInformation="false" + @bind-SelectedShapeId="@SelectedShapeId" ReadOnly="@ReadOnly">
@@ -126,7 +125,7 @@ @foreach (var shape in Shapes) { -
+
@(shape.ShapeType.ToString()):

(Id: @shape.CustomId)

@@ -139,6 +138,7 @@ else { + }
diff --git a/BlazorSvgEditor.WasmTest/Pages/Preview.razor.cs b/BlazorSvgEditor.WasmTest/Pages/Preview.razor.cs index 97f34bf..cb3754a 100644 --- a/BlazorSvgEditor.WasmTest/Pages/Preview.razor.cs +++ b/BlazorSvgEditor.WasmTest/Pages/Preview.razor.cs @@ -9,7 +9,6 @@ public partial class Preview { private SvgEditor? svgEditor; private int SelectedShapeId { get; set; } - private int ClickedShapeId { get; set; } private bool ReadOnly { get; set; } = false; @@ -113,9 +112,11 @@ private void DeleteShape() { svgEditor?.RemoveSelectedShape(); } - - void EditorShapeClicked(int CustomId) + + private async Task ZoomToShape() { - ClickedShapeId = CustomId; + if (svgEditor == null) return; + if (SelectedShapeId <= 0) return; + await svgEditor.ZoomToShape(SelectedShapeId); } } \ No newline at end of file