Skip to content

Commit

Permalink
Add VirtualizationBehavior and VirtualizationOptions and Visible prop…
Browse files Browse the repository at this point in the history
…erty on Model
  • Loading branch information
zHaytam committed Sep 9, 2022
1 parent e1d1f0f commit 062adea
Show file tree
Hide file tree
Showing 15 changed files with 155 additions and 57 deletions.
2 changes: 1 addition & 1 deletion samples/SharedDemo/Demos/Simple.razor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ protected override void OnInitialized()
protected void TogglePanning() => BlazorDiagram.Options.AllowPanning = !BlazorDiagram.Options.AllowPanning;

protected void ToggleVirtualization()
=> BlazorDiagram.Options.EnableVirtualization = !BlazorDiagram.Options.EnableVirtualization;
=> BlazorDiagram.Options.Virtualization.Enabled = !BlazorDiagram.Options.Virtualization.Enabled;

private NodeModel NewNode(double x, double y)
{
Expand Down
69 changes: 69 additions & 0 deletions src/Blazor.Diagrams.Core/Behaviors/VirtualizationBehavior.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
using Blazor.Diagrams.Core.Models.Base;

namespace Blazor.Diagrams.Core.Behaviors;

public class VirtualizationBehavior : Behavior
{
public VirtualizationBehavior(Diagram diagram) : base(diagram)
{
Diagram.ZoomChanged += CheckVisibility;
Diagram.PanChanged += CheckVisibility;
Diagram.ContainerChanged += CheckVisibility;
}

private void CheckVisibility()
{
if (!Diagram.Options.Virtualization.Enabled)
return;

if (Diagram.Container == null)
return;

if (Diagram.Options.Virtualization.OnNodes)
{
foreach (var node in Diagram.Nodes)
{
CheckVisibility(node);
}
}

if (Diagram.Options.Virtualization.OnGroups)
{
foreach (var group in Diagram.Groups)
{
CheckVisibility(group);
}
}

if (Diagram.Options.Virtualization.OnLinks)
{
foreach (var link in Diagram.Links)
{
CheckVisibility(link);
}
}
}

private void CheckVisibility(Model model)
{
if (model is not IHasBounds ihb)
return;

var bounds = ihb.GetBounds();
if (bounds == null)
return;

var left = bounds.Left * Diagram.Zoom + Diagram.Pan.X;
var top = bounds.Top * Diagram.Zoom + Diagram.Pan.Y;
var right = left + bounds.Width * Diagram.Zoom;
var bottom = top + bounds.Height * Diagram.Zoom;
model.Visible = right > 0 && left < Diagram.Container!.Width && bottom > 0 && top < Diagram.Container.Height;
}

public override void Dispose()
{
Diagram.ZoomChanged -= CheckVisibility;
Diagram.PanChanged -= CheckVisibility;
Diagram.ContainerChanged -= CheckVisibility;
}
}
1 change: 1 addition & 0 deletions src/Blazor.Diagrams.Core/Diagram.cs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ protected Diagram()
RegisterBehavior(new EventsBehavior(this));
RegisterBehavior(new KeyboardShortcutsBehavior(this));
RegisterBehavior(new ControlsBehavior(this));
RegisterBehavior(new VirtualizationBehavior(this));
}

public abstract DiagramOptions Options { get; }
Expand Down
2 changes: 1 addition & 1 deletion src/Blazor.Diagrams.Core/Models/Base/BaseLinkModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ public void SetTarget(Anchor? anchor)
public Rectangle? GetBounds()
{
if (Paths.Length == 0)
return Rectangle.Zero;
return null;

var minX = double.PositiveInfinity;
var minY = double.PositiveInfinity;
Expand Down
15 changes: 15 additions & 0 deletions src/Blazor.Diagrams.Core/Models/Base/Model.cs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ namespace Blazor.Diagrams.Core.Models.Base
{
public abstract class Model
{
private bool _visible = true;

public Model() : this(Guid.NewGuid().ToString()) { }

public Model(string id)
Expand All @@ -12,9 +14,22 @@ public Model(string id)
}

public event Action<Model>? Changed;
public event Action<Model>? VisibilityChanged;

public string Id { get; }
public bool Locked { get; set; }
public bool Visible
{
get => _visible;
set
{
if (_visible == value)
return;

_visible = value;
VisibilityChanged?.Invoke(this);
}
}

public virtual void Refresh() => Changed?.Invoke(this);
}
Expand Down
2 changes: 1 addition & 1 deletion src/Blazor.Diagrams.Core/Options/DiagramOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ public class DiagramOptions
public int? GridSize { get; set; }
public bool AllowMultiSelection { get; set; } = true;
public bool AllowPanning { get; set; } = true;
public bool EnableVirtualization { get; set; } = true; // Todo: behavior

public virtual DiagramZoomOptions Zoom { get; } = new();
public virtual DiagramLinkOptions Links { get; } = new();
public virtual DiagramGroupOptions Groups { get; } = new();
public virtual DiagramConstraintsOptions Constraints { get; } = new();
public virtual DiagramVirtualizationOptions Virtualization { get; } = new();
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
namespace Blazor.Diagrams.Core.Options;

public class DiagramVirtualizationOptions
{
public bool Enabled { get; set; }
public bool OnNodes { get; set; } = true;
public bool OnGroups { get; set; }
public bool OnLinks { get; set; }
}
10 changes: 5 additions & 5 deletions src/Blazor.Diagrams/Blazor.Diagrams.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -19,12 +19,12 @@
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Components" Version="6.0.0"/>
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="6.0.0"/>
<PackageReference Include="Microsoft.AspNetCore.Components" Version="6.0.0" />
<PackageReference Include="Microsoft.AspNetCore.Components.Web" Version="6.0.0" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Blazor.Diagrams.Core\Blazor.Diagrams.Core.csproj"/>
<ProjectReference Include="..\Blazor.Diagrams.Core\Blazor.Diagrams.Core.csproj" />
</ItemGroup>

<ItemGroup>
Expand All @@ -37,12 +37,12 @@
<Target Name="TestWebCompiler" AfterTargets="BeforeBuild">
<!-- Test if Excubo.WebCompiler is installed (recommended) -->
<Exec Command="webcompiler -h" ContinueOnError="true" StandardOutputImportance="low" StandardErrorImportance="low" LogStandardErrorAsError="false" IgnoreExitCode="true">
<Output TaskParameter="ExitCode" PropertyName="ErrorCode"/>
<Output TaskParameter="ExitCode" PropertyName="ErrorCode" />
</Exec>
</Target>

<Target Name="CompileStaticAssets" AfterTargets="CoreCompile;TestWebCompiler" Condition="'$(ErrorCode)' == '0'">
<Exec Command="webcompiler -r wwwroot" StandardOutputImportance="high" StandardErrorImportance="high"/>
<Exec Command="webcompiler -r wwwroot" StandardOutputImportance="high" StandardErrorImportance="high" />
</Target>

</Project>
6 changes: 3 additions & 3 deletions src/Blazor.Diagrams/Components/DiagramCanvas.razor
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@
@onpointermove:preventDefault
@onwheel:stopPropagation>

@* Links *@
<svg class="diagram-svg-layer" style="@GetLayerStyle(BlazorDiagram.Options.LinksLayerOrder)">
@foreach (var node in BlazorDiagram.Nodes.OfType<SvgNodeModel>().Where(n => n.Group == null))
{
Expand All @@ -29,11 +28,12 @@
<ControlsLayerRenderer Svg="@true"></ControlsLayerRenderer>
</svg>

@* Nodes *@
<div class="diagram-html-layer" style="@GetLayerStyle(BlazorDiagram.Options.NodesLayerOrder)">
@foreach (var group in BlazorDiagram.Groups.Where(n => n is not SvgGroupModel))
{
if (group.Group != null) continue;
if (group.Group != null)
continue;

<GroupRenderer @key="group" Group="group"/>
}

Expand Down
5 changes: 5 additions & 0 deletions src/Blazor.Diagrams/Components/Renderers/GroupRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@ public class GroupRenderer : ComponentBase, IDisposable
public void Dispose()
{
Group.Changed -= OnGroupChanged;
Group.VisibilityChanged -= OnGroupChanged;
}

protected override void OnInitialized()
{
Group.Changed += OnGroupChanged;
Group.VisibilityChanged += OnGroupChanged;
}

protected override void OnParametersSet()
Expand Down Expand Up @@ -78,6 +80,9 @@ private static string GenerateStyle(double top, double left, double width, doubl

protected override void BuildRenderTree(RenderTreeBuilder builder)
{
if (!Group.Visible)
return;

var componentType = BlazorDiagram.GetComponent(Group) ?? typeof(DefaultGroupWidget);
var classes = new StringBuilder("group")
.AppendIf(" locked", Group.Locked)
Expand Down
16 changes: 10 additions & 6 deletions src/Blazor.Diagrams/Components/Renderers/LinkRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,31 @@ public class LinkRenderer : ComponentBase, IDisposable
public void Dispose()
{
Link.Changed -= OnLinkChanged;
Link.VisibilityChanged -= OnLinkChanged;
}

protected override void OnInitialized()
{
base.OnInitialized();

Link.Changed += OnLinkChanged;
Link.VisibilityChanged += OnLinkChanged;
}

protected override bool ShouldRender()
{
return _shouldRender;
if (!_shouldRender)
return false;

_shouldRender = false;
return true;
}

protected override void BuildRenderTree(RenderTreeBuilder builder)
{
if (!Link.Visible)
return;

var componentType = BlazorDiagram.GetComponent(Link) ?? typeof(LinkWidget);

builder.OpenElement(0, "g");
Expand All @@ -51,11 +60,6 @@ protected override void BuildRenderTree(RenderTreeBuilder builder)
builder.CloseElement();
}

protected override void OnAfterRender(bool firstRender)
{
_shouldRender = false;
}

private void OnLinkChanged(Model _)
{
_shouldRender = true;
Expand Down
44 changes: 11 additions & 33 deletions src/Blazor.Diagrams/Components/Renderers/NodeRenderer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,6 @@ public class NodeRenderer : ComponentBase, IDisposable
private bool _becameVisible;
private ElementReference _element;
private bool _isSvg;
private bool _isVisible = true;
private DotNetObjectReference<NodeRenderer>? _reference;
private bool _shouldRender;

Expand All @@ -31,10 +30,8 @@ public class NodeRenderer : ComponentBase, IDisposable

public void Dispose()
{
BlazorDiagram.PanChanged -= CheckVisibility;
BlazorDiagram.ZoomChanged -= CheckVisibility;
BlazorDiagram.ContainerChanged -= CheckVisibility;
Node.Changed -= OnNodeChanged;
Node.VisibilityChanged -= OnVisibilityChanged;

if (_element.Id != null)
_ = JsRuntime.UnobserveResizes(_element);
Expand Down Expand Up @@ -65,10 +62,8 @@ protected override void OnInitialized()
base.OnInitialized();

_reference = DotNetObjectReference.Create(this);
BlazorDiagram.PanChanged += CheckVisibility;
BlazorDiagram.ZoomChanged += CheckVisibility;
BlazorDiagram.ContainerChanged += CheckVisibility;
Node.Changed += OnNodeChanged;
Node.VisibilityChanged += OnVisibilityChanged;
}

protected override void OnParametersSet()
Expand All @@ -89,7 +84,7 @@ protected override bool ShouldRender()

protected override void BuildRenderTree(RenderTreeBuilder builder)
{
if (!_isVisible)
if (!Node.Visible)
return;

var componentType = BlazorDiagram.GetComponent(Node) ??
Expand All @@ -104,11 +99,15 @@ protected override void BuildRenderTree(RenderTreeBuilder builder)
builder.AddAttribute(2, "data-node-id", Node.Id);

if (_isSvg)
{
builder.AddAttribute(3, "transform",
$"translate({Node.Position.X.ToInvariantString()} {Node.Position.Y.ToInvariantString()})");
}
else
{
builder.AddAttribute(3, "style",
$"top: {Node.Position.Y.ToInvariantString()}px; left: {Node.Position.X.ToInvariantString()}px");
}

builder.AddAttribute(4, "onpointerdown", EventCallback.Factory.Create<PointerEventArgs>(this, OnPointerDown));
builder.AddEventStopPropagationAttribute(5, "onpointerdown", true);
Expand All @@ -126,42 +125,21 @@ protected override void BuildRenderTree(RenderTreeBuilder builder)

protected override async Task OnAfterRenderAsync(bool firstRender)
{
await base.OnAfterRenderAsync(firstRender);

if (firstRender || _becameVisible)
{
_becameVisible = false;
await JsRuntime.ObserveResizes(_element, _reference);
}
}

private void CheckVisibility()
private void OnNodeChanged(Model _)
{
// _isVisible must be true in case virtualization gets disabled and some nodes are hidden
if (!BlazorDiagram.Options.EnableVirtualization && _isVisible)
return;

if (Node.Size == null)
return;

var left = Node.Position.X * BlazorDiagram.Zoom + BlazorDiagram.Pan.X;
var top = Node.Position.Y * BlazorDiagram.Zoom + BlazorDiagram.Pan.Y;
var right = left + Node.Size.Width * BlazorDiagram.Zoom;
var bottom = top + Node.Size.Height * BlazorDiagram.Zoom;

var isVisible = right > 0 && left < BlazorDiagram.Container.Width && bottom > 0 &&
top < BlazorDiagram.Container.Height;

if (_isVisible != isVisible)
{
_isVisible = isVisible;
_becameVisible = isVisible;
ReRender();
}
ReRender();
}

private void OnNodeChanged(Model _)
private void OnVisibilityChanged(Model _)
{
_becameVisible = Node.Visible;
ReRender();
}

Expand Down
Loading

0 comments on commit 062adea

Please sign in to comment.