Blazor-Diagrams / Blazor.Diagrams

A fully customizable and extensible all-purpose diagrams library for Blazor
https://blazor-diagrams.zhaytam.com
MIT License
1.01k stars 205 forks source link

Link dblclick segmentable #431

Open snakex64 opened 6 months ago

snakex64 commented 6 months ago

I added a new option to make link segmentable only with double click instead of single clicks.

I also took the opportunity to add events for vertex added and removed, since there was no way of knowing the vertex changed other than cycling through all of them everytime there is a "Changed" event

PiggyChu620 commented 5 months ago

Hello, I tried to utilize your modification through inheritance, but I don't how to "replace" the original widget and renderer with yours, I can't seem to find where it was registered in the vanilla source code. Could you please be so kind teaching me how to do it? Much appreciated!

snakex64 commented 5 months ago

Hello, I tried to utilize your modification through inheritance, but I don't how to "replace" the original widget and renderer with yours, I can't seem to find where it was registered in the vanilla source code. Could you please be so kind teaching me how to do it? Much appreciated!

I am not quite sure that it can be done at all! Since I have multiple PR that are not being merged I ended up just using my fork directly.

I have a "up-to-date" branch that I merged my other branches in it, and I keep it up to date with this repo. That way I have the updates and my own changes :

https://github.com/snakex64/Blazor.Diagrams/tree/up-to-date

Then, in my actual project, I just added that branche as a subrepo git and reference the csproj directly instead of the official nuget package :)

PiggyChu620 commented 5 months ago

Hello, I tried to utilize your modification through inheritance, but I don't how to "replace" the original widget and renderer with yours, I can't seem to find where it was registered in the vanilla source code. Could you please be so kind teaching me how to do it? Much appreciated!

I am not quite sure that it can be done at all! Since I have multiple PR that are not being merged I ended up just using my fork directly.

I have a "up-to-date" branch that I merged my other branches in it, and I keep it up to date with this repo. That way I have the updates and my own changes :

https://github.com/snakex64/Blazor.Diagrams/tree/up-to-date

Then, in my actual project, I just added that branche as a subrepo git and reference the csproj directly instead of the official nuget package :)

OK, thanks. Have you release your own NuGet package by any chance? I don't know about legal issues and whatnot, but it'll awesome if we could install your branch directly from NuGet, because I hate to say, seems like the original creator(s) has gave up on updating this package, I mean, there are so many great minds like you helping this project grow, but the creator(s) is so relunctant to review them, let along merge them, I have to say that it's a total shame!

Btw, I have figured out how to implement your changes through inheritance (finally!): How to implement Pull Requests that is not yet being merged

jokerclay commented 2 months ago

I have a similar requirement to create a vertex with a double-click.


public class CreateLinkVerticesBehavior : Behavior
{
    public CreateLinkVerticesBehavior(Blazor.Diagrams.Core.Diagram diagram) : base(diagram)
    {
        diagram.PointerDoubleClick += OnPointerDoubleClick;
    }

    private void OnPointerDoubleClick(Model? model, PointerEventArgs args)
    {

        if (model is BehaviorLinkModel link)
        {
            var rPt = Diagram.GetRelativeMousePoint(args.ClientX, args.ClientY);
            // Determine the correct index to insert the vertex
            int index = DetermineInsertionIndex(link, rPt);

            var vertex = new LinkVertexModel(link, rPt);
            link.Vertices.Insert(index, vertex);
            link.Refresh();
        }
    }

    private int DetermineInsertionIndex(LinkModel link, Point rPt)
    {
        if (!link.Vertices.Any())
            return 0;

        double minDistance = double.MaxValue;
        int insertIndex = link.Vertices.Count;

        var sourcePort = (link.Source as SinglePortAnchor)?.Port;
        var targetPort = (link.Target as SinglePortAnchor)?.Port;

        var sourcePortPosition = new Point(sourcePort!.Position.X, sourcePort.Position.Y);
        var targetPortPosition = new Point(targetPort!.Position.X, targetPort.Position.Y);

        // Check distance to the segment from source port to the first vertex
        if (link.Vertices.Any())
        {
            var firstVertexPosition = new Point(link.Vertices[0].Position.X, link.Vertices[0].Position.Y);
            double distance = DistanceFromPointToSegment(rPt, sourcePortPosition, firstVertexPosition);
            if (distance < minDistance)
            {
                minDistance = distance;
                insertIndex = 0;
            }

            // Check distances to segments between vertices
            for (int i = 0; i < link.Vertices.Count - 1; i++)
            {
                var startPoint = new Point(link.Vertices[i].Position.X, link.Vertices[i].Position.Y);
                var endPoint = new Point(link.Vertices[i + 1].Position.X, link.Vertices[i + 1].Position.Y);
                distance = DistanceFromPointToSegment(rPt, startPoint, endPoint);

                if (distance < minDistance)
                {
                    minDistance = distance;
                    insertIndex = i + 1;
                }
            }

            // Check distance to the segment from the last vertex to the target port
            var lastVertexPosition = new Point(link.Vertices[^1].Position.X, link.Vertices[^1].Position.Y);
            distance = DistanceFromPointToSegment(rPt, lastVertexPosition, targetPortPosition);
            if (distance < minDistance)
            {
                minDistance = distance;
                insertIndex = link.Vertices.Count;
            }
        }
        else
        {
            // If there are no vertices, check the segment from source port to target port
            double distance = DistanceFromPointToSegment(rPt, sourcePortPosition, targetPortPosition);
            if (distance < minDistance)
            {
                minDistance = distance;
                insertIndex = 0;
            }
        }

        return insertIndex;
    }

    private double DistanceFromPointToSegment(Point point, Point start, Point end)
    {
        double dx = end.X - start.X;
        double dy = end.Y - start.Y;

        if (dx == 0 && dy == 0)
            return Math.Sqrt(Math.Pow(point.X - start.X, 2) + Math.Pow(point.Y - start.Y, 2));

        double t = ((point.X - start.X) * dx + (point.Y - start.Y) * dy) / (dx * dx + dy * dy);
        t = Math.Max(0, Math.Min(1, t));

        double projX = start.X + t * dx;
        double projY = start.Y + t * dy;

        return Math.Sqrt(Math.Pow(point.X - projX, 2) + Math.Pow(point.Y - projY, 2));
    }

    public override void Dispose()
    {
        Diagram.PointerDown -= OnPointerDoubleClick;
    }
}
zHaytam commented 2 months ago

Hello, sorry for the delay!

Could you check the comment? After that I can merge this.