Skip to content

Commit

Permalink
add functionality to zoom to a specified shape
Browse files Browse the repository at this point in the history
  • Loading branch information
florian03-1 committed Mar 8, 2024
1 parent 51eeb8c commit bfa6af9
Show file tree
Hide file tree
Showing 9 changed files with 100 additions and 13 deletions.
2 changes: 1 addition & 1 deletion BlazorSvgEditor.SvgEditor/Shapes/Circle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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()
{
Expand Down
2 changes: 1 addition & 1 deletion BlazorSvgEditor.SvgEditor/Shapes/Polygon.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
2 changes: 1 addition & 1 deletion BlazorSvgEditor.SvgEditor/Shapes/Rectangle.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ public Rectangle(SvgEditor svgEditor) : base(svgEditor){ }

private Coord<double> 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()
{
Expand Down
2 changes: 1 addition & 1 deletion BlazorSvgEditor.SvgEditor/Shapes/Shape.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
57 changes: 57 additions & 0 deletions BlazorSvgEditor.SvgEditor/SvgEditor.PublicMethods.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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<double>? newTranslate = null, double? newScale = null)
Expand Down
29 changes: 29 additions & 0 deletions BlazorSvgEditor.SvgEditor/SvgEditor.Transformations.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using BlazorSvgEditor.SvgEditor.Helper;
using BlazorSvgEditor.SvgEditor.Misc;
using Microsoft.AspNetCore.Components.Web;

namespace BlazorSvgEditor.SvgEditor;
Expand Down Expand Up @@ -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);

Expand Down
2 changes: 1 addition & 1 deletion BlazorSvgEditor.SvgEditor/SvgEditor.razor
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
<b>ContainerBox:</b> X: @(Math.Round(_containerBoundingBox.Width, 1))px Y: @(Math.Round(_containerBoundingBox.Height, 1))px
</foreignObject>

<foreignObject visibility="hidden" height="120px" width="300px" class="unselectable" x="0px" y="150" style="font-size:14px;pointer-events:none;touch-action:none; background-color: white">
<foreignObject height="120px" width="300px" class="unselectable" x="0px" y="150" style="font-size:14px;pointer-events:none;touch-action:none; background-color: white">
@foreach(var shape in Shapes)
{
@shape.ToString()
Expand Down
8 changes: 4 additions & 4 deletions BlazorSvgEditor.WasmTest/Pages/Preview.razor
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,8 @@

<div class="o-editor">
<SvgEditor @ref="svgEditor" CssClass="border border-gray-200 rounded-lg shadow-md" MinScale="0.8" ImageSize="(1000,750)" ImageManipulations="ImageManipulations"
OnShapeChanged="EditorShapeChanged" ImageSourceLoadingFunc="GetImageSource"
OnShapeClicked="EditorShapeClicked"
@bind-SelectedShapeId="SelectedShapeId" ReadOnly="ReadOnly">
OnShapeChanged="EditorShapeChanged" ImageSourceLoadingFunc="GetImageSource" ShowDiagnosticInformation="false"
@bind-SelectedShapeId="@SelectedShapeId" ReadOnly="@ReadOnly">
<LoadingSpinner>

<div class="flex items-center justify-center h-full">
Expand Down Expand Up @@ -126,7 +125,7 @@

@foreach (var shape in Shapes)
{
<div @onclick="() => ShapeSelected(shape.CustomId)" class="cursor-pointer border border-gray-300 p-1.5 inline-flex rounded-lg mb-2 @(((shape.CustomId == SelectedShapeId) || (shape.CustomId == ClickedShapeId)) ? "border-red-900 bg-red-300" : "")">
<div @onclick="() => ShapeSelected(shape.CustomId)" class="cursor-pointer border border-gray-300 p-1.5 inline-flex rounded-lg mb-2 @(((shape.CustomId == SelectedShapeId)) ? "border-red-900 bg-red-300" : "")">
<b class="mr-2">@(shape.ShapeType.ToString()):</b>
<p>(Id: @shape.CustomId)</p>
</div>
Expand All @@ -139,6 +138,7 @@
else
{
<button @onclick="DeleteShape" type="button" style="flex-grow: 0" class=" shadow-sm flex-grow focus:outline-none text-white bg-red-700 hover:bg-red-800 focus:ring-4 focus:ring-red-300 font-medium rounded-lg text-sm px-5 py-2">Delete Shape</button>
<button @onclick="ZoomToShape" type="button" style="flex-grow: 0" class="mt-2 shadow-sm flex-grow focus:outline-none text-white bg-yellow-400 hover:bg-yellow-500 focus:ring-4 focus:ring-yellow-300 font-medium rounded-lg text-sm px-5 py-2">Zoom to Shape</button>
}

</div>
Expand Down
9 changes: 5 additions & 4 deletions BlazorSvgEditor.WasmTest/Pages/Preview.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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;


Expand Down Expand Up @@ -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);
}
}

0 comments on commit bfa6af9

Please sign in to comment.