|
7 | 7 |
|
8 | 8 | A simple graph editor for Blazor. |
9 | 9 |
|
| 10 | + |
| 11 | + |
10 | 12 | # Demo |
11 | 13 | The WASM sample project can be demoed at [https://kristofferstrube.github.io/Blazor.GraphEditor/](https://kristofferstrube.github.io/Blazor.GraphEditor/) |
12 | 14 |
|
13 | | - |
| 15 | +# Getting Started |
| 16 | +## Prerequisites |
| 17 | +You need to install .NET 7.0 or newer to use the library. |
| 18 | + |
| 19 | +[Download .NET 7](https://dotnet.microsoft.com/download/dotnet/7.0) |
| 20 | + |
| 21 | +## Installation |
| 22 | +You can install the package via NuGet with the Package Manager in your IDE or alternatively using the command line: |
| 23 | +```bash |
| 24 | +dotnet add package KristofferStrube.Blazor.SVGEditor |
| 25 | +``` |
| 26 | +The package can be used in Blazor WebAssembly and Blazor Server projects. In the samples folder of this repository, you can find two projects that show how to use the `SVGEditor` component in both Blazor Server and WASM. |
| 27 | + |
| 28 | +## Import |
| 29 | +You need to reference the package to use it in your pages. This can be done in `_Import.razor` by adding the following. |
| 30 | +```razor |
| 31 | +@using KristofferStrube.Blazor.GraphEditor |
| 32 | +``` |
| 33 | + |
| 34 | +## Add to service collection |
| 35 | +To use the component in your pages you also need to register som services in your service collection. We have a single method that is exposed via the **Blazor.SVGEditor** library which adds all these services. |
| 36 | + |
| 37 | +```csharp |
| 38 | +var builder = WebAssemblyHostBuilder.CreateDefault(args); |
| 39 | +builder.RootComponents.Add<App>("#app"); |
| 40 | +builder.RootComponents.Add<HeadOutlet>("head::after"); |
| 41 | + |
| 42 | +builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) }); |
| 43 | + |
| 44 | +// Adding the needed services. |
| 45 | +builder.Services.AddSVGEditor(); |
| 46 | + |
| 47 | +await builder.Build().RunAsync(); |
| 48 | +``` |
| 49 | + |
| 50 | +## Include needed stylesheets and scripts |
| 51 | +The libraries that the component uses also need to have some stylesheets and scripts added to function. |
| 52 | +For this, you need to insert the following tags in the `<head>` section of your `index.html` or `Host.cshtml` file: |
| 53 | +```html |
| 54 | +<link href="_content/BlazorColorPicker/colorpicker.css" rel="stylesheet" /> |
| 55 | +<link href="_content/Blazor.ContextMenu/blazorContextMenu.min.css" rel="stylesheet" /> |
| 56 | +<link href="_content/KristofferStrube.Blazor.SVGEditor/kristofferStrubeBlazorSVGEditor.css" rel="stylesheet" /> |
| 57 | +``` |
| 58 | +The library uses Scoped CSS, so you must include your project-specific `.styles.css` CSS file in your project for the scoped styles of the library components. An example is in the test project in this repo: |
| 59 | +```html |
| 60 | +<link href="KristofferStrube.Blazor.GraphEditor.WasmExample.styles.css" rel="stylesheet" /> |
| 61 | +``` |
| 62 | + |
| 63 | +At the end of the file, after you have referenced the Blazor Server or Wasm bootstrapper, insert the following: |
| 64 | + |
| 65 | +```html |
| 66 | +<script src="_content/Blazor.ContextMenu/blazorContextMenu.min.js"></script> |
| 67 | +``` |
| 68 | + |
| 69 | +## Adding the component to a site. |
| 70 | +Now, you are ready to use the component in your page. A minimal example of this would be the following: |
| 71 | + |
| 72 | +```razor |
| 73 | +<div style="height:80vh;"> |
| 74 | + <GraphEditor |
| 75 | + @ref=GraphEditor |
| 76 | + TNode="Page" |
| 77 | + TEdge="Transition" |
| 78 | + NodeIdMapper="n => n.id" |
| 79 | + NodeRadiusMapper="n => n.size" |
| 80 | + NodeColorMapper="n => n.color" |
| 81 | + EdgeFromMapper="e => e.from" |
| 82 | + EdgeToMapper="e => e.to" |
| 83 | + EdgeWidthMapper="e => e.weight*5" |
| 84 | + EdgeSpringConstantMapper="e => e.weight" |
| 85 | + EdgeSpringLengthMapper="e => e.length" |
| 86 | + /> |
| 87 | +</div> |
| 88 | +@code { |
| 89 | + private GraphEditor.GraphEditor<Page, Transition> GraphEditor = default!; |
| 90 | + private bool running = true; |
| 91 | +
|
| 92 | + protected override async Task OnAfterRenderAsync(bool firstRender) |
| 93 | + { |
| 94 | + if (!firstRender) return; |
| 95 | + while (!GraphEditor.IsReadyToLoad) |
| 96 | + { |
| 97 | + await Task.Delay(50); |
| 98 | + } |
| 99 | +
|
| 100 | + var pages = new List<Page>() { new("1", size: 60), new("2", "#3333AA"), new("3", "#AA33AA"), new("4", "#AA3333"), new("5", "#AAAA33"), new("6", "#33AAAA"), new("7"), new("8") }; |
| 101 | +
|
| 102 | + var edges = new List<Transition>() { |
| 103 | + new(pages[0], pages[1], 1), |
| 104 | + new(pages[0], pages[2], 1), |
| 105 | + new(pages[0], pages[3], 1), |
| 106 | + new(pages[0], pages[4], 1), |
| 107 | + new(pages[0], pages[5], 1), |
| 108 | + new(pages[0], pages[6], 1), |
| 109 | + new(pages[6], pages[7], 2, 150) }; |
| 110 | +
|
| 111 | + await GraphEditor.LoadGraph(pages, edges); |
| 112 | +
|
| 113 | + DateTimeOffset startTime = DateTimeOffset.UtcNow; |
| 114 | + while (running) |
| 115 | + { |
| 116 | + await GraphEditor.ForceDirectedLayout(); |
| 117 | + /// First 5 seconds also fit the viewport to all the nodes and edges in the graph. |
| 118 | + if (startTime - DateTimeOffset.UtcNow < TimeSpan.FromSeconds(5)) |
| 119 | + GraphEditor.SVGEditor.FitViewportToAllShapes(delta: 0.8); |
| 120 | + await Task.Delay(1); |
| 121 | + } |
| 122 | + } |
| 123 | +
|
| 124 | + public record Page(string id, string color = "#66BB6A", float size = 50); |
| 125 | + public record Transition(Page from, Page to, float weight, float length = 200); |
| 126 | +
|
| 127 | + public void Dispose() |
| 128 | + { |
| 129 | + running = false; |
| 130 | + } |
| 131 | +} |
| 132 | +``` |
0 commit comments