Blazor-Diagrams / Blazor.Diagrams

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

Zoom in & Zoom out through buttons not working as expected #151

Open Manjunath1205 opened 3 years ago

Manjunath1205 commented 3 years ago

When tried to zoom in the diagram it moves towards right instead of zooming the middle of the screen. Zoom through mouse scroll bar is working fine but not using the buttons.

This is what I am doing onclick <button class="btn" @onclick="()=> { _diagram.SetZoom(_diagram.Zoom + 0.1);}>

Attaching the screenshot for reference. image

zHaytam commented 3 years ago

Hello! This is normal as SetZoom only changes the zoom. What you need is the same calculation as the wheel zoom (but always from the center), which also changes the Pan. You can look at ZoomBehavior if you're willing to implement it.

If you can wait a bit more, I can add a sample code here. Although I will make sure to add it in a future version!

Manjunath1205 commented 3 years ago

Thanks for your acknowledgement.

We would definitely require sample code. Your help is solicited.

zHaytam commented 3 years ago

Hello, can you please try the following sample:

var oldZoom = diagram.Zoom;
var newZoom = diagram.Zoom + 0.1;
newZoom = Math.Clamp(newZoom, diagram.Options.Zoom.Minimum, diagram.Options.Zoom.Maximum);

if (newZoom < 0 || newZoom == diagram.Zoom)
    return;

var clientWidth = diagram.Container.Width;
var clientHeight = diagram.Container.Height;
var widthDiff = clientWidth * newZoom - clientWidth * oldZoom;
var heightDiff = clientHeight * newZoom - clientHeight * oldZoom;
var clientX = (clientWidth / 2);
var clientY = (clientHeight / 2);
var xFactor = (clientX - diagram.Pan.X) / oldZoom / clientWidth;
var yFactor = (clientY - diagram.Pan.Y) / oldZoom / clientHeight;
var newPanX = diagram.Pan.X - widthDiff * xFactor;
var newPanY = diagram.Pan.Y - heightDiff * yFactor;

diagram.Batch(() =>
{
    diagram.SetPan(newPanX, newPanY);
    diagram.SetZoom(newZoom);
});
Manjunath1205 commented 3 years ago

Thanks for the code @zHaytam.

I tried the code which you have shared as below, but the application is getting crashed.

<button class="btn" @onclick="()=> ZoomIn()">

@code { public void ZoomIn() { _diagram.SuspendRefresh = true; var oldZoom = _diagram.Zoom; var newZoom = _diagram.Zoom + 0.1; newZoom = Math.Clamp(newZoom, _diagram.Options.Zoom.Minimum, _diagram.Options.Zoom.Maximum);

    if (newZoom < 0 || newZoom == _diagram.Zoom)
        return;

    var clientWidth = _diagram.Container.Width;
    var clientHeight = _diagram.Container.Height;
    var widthDiff = clientWidth * newZoom - clientWidth * oldZoom;
    var heightDiff = clientHeight * newZoom - clientHeight * oldZoom;
    var clientX = (clientWidth / 2);
    var clientY = (clientHeight / 2);
    var xFactor = (clientX - _diagram.Pan.X) / oldZoom / clientWidth;
    var yFactor = (clientY - _diagram.Pan.Y) / oldZoom / clientHeight;
    var newPanX = _diagram.Pan.X - widthDiff * xFactor;
    var newPanY = _diagram.Pan.Y - heightDiff * yFactor;

    _diagram.Batch(() =>
    {
        _diagram.UpdatePan(newPanX, newPanY);
        _diagram.SetZoom(newZoom);
    });
    _diagram.SuspendRefresh = false;
    _diagram.Refresh();
}

}

If I just try below mentioned code the application is not crashing public void ZoomIn() { _diagram.SetZoom(_diagram.Zoom + 0.1); }

zHaytam commented 3 years ago

What's the error/exception?

Manjunath1205 commented 3 years ago

Following is the exception that I am getting.

This issue occurs even while trying to Pan, zoom using mouse(these two instances are happening rarely)

_Microsoft.JSInterop.JSException: Failed to execute 'observe' on 'ResizeObserver': parameter 1 is not of type 'Element'. TypeError: Failed to execute 'observe' on 'ResizeObserver': parameter 1 is not of type 'Element'. at Object.observe (https://localhost:5001/_content/Z.Blazor.Diagrams/script.min.js:1:583) at https://localhost:5001/_framework/blazor.server.js:1:70045 at new Promise () at e.beginInvokeJSFromDotNet (https://localhost:5001/_framework/blazor.server.js:1:70011) at https://localhost:5001/_framework/blazor.server.js:1:26293 at Array.forEach () at e.invokeClientMethod (https://localhost:5001/_framework/blazor.server.js:1:26263) at e.processIncomingData (https://localhost:5001/_framework/blazor.server.js:1:24201) at e.connection.onreceive (https://localhost:5001/_framework/blazor.server.js:1:17286) at WebSocket.i.onmessage (https://localhost:5001/_framework/blazor.server.js:1:46503) at Microsoft.JSInterop.JSRuntime.InvokeAsync[TValue](Int64 targetInstanceId, String identifier, Object[] args) at Microsoft.JSInterop.JSRuntimeExtensions.InvokeVoidAsync(IJSRuntime jsRuntime, String identifier, Object[] args) at Blazor.Diagrams.Extensions.JSRuntimeExtensions.ObserveResizes[T](IJSRuntime jsRuntime, ElementReference element, DotNetObjectReference`1 reference) at Blazor.Diagrams.Components.Renderers.NodeRenderer.OnAfterRenderAsync(Boolean firstRender) at Microsoft.AspNetCore.Components.RenderTree.Renderer.GetErrorHandledTask(Task taskToHandle)_

zHaytam commented 3 years ago

This is very weird. So if I'm understanding correctly, you click your button, which calls ZoomIn, and it throws this exact exception?

Manjunath1205 commented 3 years ago

For the first time when I click on zoomin it doesn't throw any exception, but when I try for second time it throws this exception. Following are the steps I followed. 1) Pan the diagram to center of the screen. 2) Click on zoomin, calls zoomin function - works fine in the first attempt. 3) Click on zoomin again then this exception occurs.

zHaytam commented 3 years ago

Did you switch to Version 2.1.6 by any chance?

Manjunath1205 commented 3 years ago

No.. I am currently using 2.1.5.

image

snehabihani commented 2 years ago

Can you please help with zoomin zoomout options on button click?

Delgerskhn commented 11 months ago

Hello, can you please try the following sample:

var oldZoom = diagram.Zoom;
var newZoom = diagram.Zoom + 0.1;
newZoom = Math.Clamp(newZoom, diagram.Options.Zoom.Minimum, diagram.Options.Zoom.Maximum);

if (newZoom < 0 || newZoom == diagram.Zoom)
    return;

var clientWidth = diagram.Container.Width;
var clientHeight = diagram.Container.Height;
var widthDiff = clientWidth * newZoom - clientWidth * oldZoom;
var heightDiff = clientHeight * newZoom - clientHeight * oldZoom;
var clientX = (clientWidth / 2);
var clientY = (clientHeight / 2);
var xFactor = (clientX - diagram.Pan.X) / oldZoom / clientWidth;
var yFactor = (clientY - diagram.Pan.Y) / oldZoom / clientHeight;
var newPanX = diagram.Pan.X - widthDiff * xFactor;
var newPanY = diagram.Pan.Y - heightDiff * yFactor;

diagram.Batch(() =>
{
    diagram.SetPan(newPanX, newPanY);
    diagram.SetZoom(newZoom);
});

This sample code is working fine on 3.0.1. Shall this panning logic implemented in SetZoom method ? Or should implement separate method ZoomToCenter on Diagram class?

Etzix commented 1 month ago

Since the logic is already readily available, should we not change the way SetZoom works to use this behaviour instead? Or should we create a new method?