Skip to content

Commit 04fb0a6

Browse files
committed
Mystify with Blazor
1 parent 02575fb commit 04fb0a6

File tree

18 files changed

+11688
-0
lines changed

18 files changed

+11688
-0
lines changed
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
<Router AppAssembly="@typeof(Program).Assembly">
2+
<Found Context="routeData">
3+
<RouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
4+
</Found>
5+
<NotFound>
6+
<LayoutView Layout="@typeof(MainLayout)">
7+
<p>Sorry, there's nothing at this address.</p>
8+
</LayoutView>
9+
</NotFound>
10+
</Router>
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
6+
namespace MystifyBlazor.Models
7+
{
8+
public class Color
9+
{
10+
public double Hue;
11+
12+
public Color(double hueFrac = .5) =>
13+
Hue = hueFrac;
14+
15+
public override string ToString() =>
16+
ColorFromHSV(Hue * 360);
17+
18+
/// <summary>
19+
/// Convert a hue (on 360º scale) to RGB hex string
20+
/// </summary>
21+
private static string ColorFromHSV(double hue, double saturation = 1, double value = 1)
22+
{
23+
hue %= 360;
24+
int hi = Convert.ToInt32(Math.Floor(hue / 60)) % 6;
25+
double f = hue / 60 - Math.Floor(hue / 60);
26+
27+
value *= 255;
28+
int v = Convert.ToInt32(value);
29+
int p = Convert.ToInt32(value * (1 - saturation));
30+
int q = Convert.ToInt32(value * (1 - f * saturation));
31+
int t = Convert.ToInt32(value * (1 - (1 - f) * saturation));
32+
33+
static string Hex(int r, int g, int b) => $"#{r:X2}{g:X2}{b:X2}";
34+
35+
if (hi == 0)
36+
return Hex(v, t, p);
37+
else if (hi == 1)
38+
return Hex(q, v, p);
39+
else if (hi == 2)
40+
return Hex(p, v, t);
41+
else if (hi == 3)
42+
return Hex(p, q, v);
43+
else if (hi == 4)
44+
return Hex(t, p, v);
45+
else
46+
return Hex(v, p, q);
47+
}
48+
}
49+
}
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
using System;
2+
3+
namespace MystifyBlazor.Models
4+
{
5+
/// <summary>
6+
/// A moving corner has a position and velocity
7+
/// </summary>
8+
public class Corner
9+
{
10+
public double X;
11+
public double Y;
12+
public double XVel;
13+
public double YVel;
14+
15+
public Corner() { }
16+
17+
public static Corner RandomPoint(Random rand, double width, double height) =>
18+
new Corner()
19+
{
20+
X = width * rand.NextDouble(),
21+
Y = height * rand.NextDouble(),
22+
XVel = rand.NextDouble() - .5,
23+
YVel = rand.NextDouble() - .5,
24+
};
25+
26+
public Corner(double x, double y, double xVel, double yVel) =>
27+
(X, Y, XVel, YVel) = (x, y, xVel, yVel);
28+
29+
public Corner NextPoint(double delta, double width, double height)
30+
{
31+
Corner pt = new Corner(X, Y, XVel, YVel);
32+
pt.Advance(delta, width, height);
33+
return pt;
34+
}
35+
36+
public void Advance(double delta, double width, double height)
37+
{
38+
X += XVel * delta;
39+
Y += YVel * delta;
40+
41+
if (X < 0 || X > width)
42+
XVel *= -1;
43+
if (Y < 0 || Y > height)
44+
YVel *= -1;
45+
46+
if (X < 0)
47+
X += 0 - X;
48+
else if (X > width)
49+
X -= X - width;
50+
51+
if (Y < 0)
52+
Y += 0 - Y;
53+
if (Y > height)
54+
Y -= Y - height;
55+
}
56+
}
57+
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
6+
namespace MystifyBlazor.Models
7+
{
8+
/// <summary>
9+
/// This class manages shapes (which are historical records of polygons)
10+
/// </summary>
11+
public class Field
12+
{
13+
private readonly Random rand = new Random();
14+
private List<Shape> Shapes = new List<Shape>();
15+
public int ShapeCount = 2;
16+
public int CornerCount = 4;
17+
public int HistoryCount = 5;
18+
public bool Rainbow = false;
19+
public double Speed = 20;
20+
21+
public void Advance(double width, double height)
22+
{
23+
// delete shapes with incorrect number of corners
24+
Shapes = Shapes.Where(x => x.Polygons[0].CornerCount == CornerCount).ToList();
25+
26+
// ensure correct number of shapes
27+
while (Shapes.Count < ShapeCount)
28+
Shapes.Add(new Shape(rand, CornerCount, width, height, null));
29+
while (Shapes.Count > ShapeCount)
30+
Shapes.RemoveAt(0);
31+
32+
// advance each shape
33+
foreach (var shape in Shapes)
34+
shape.Advance(Speed, width, height, HistoryCount, Rainbow);
35+
}
36+
37+
public void RandomizeColors()
38+
{
39+
for (int i = 0; i < Shapes.Count; i++)
40+
Shapes[i].Polygons.Last().Color.Hue = rand.NextDouble();
41+
}
42+
43+
public string GetJSON()
44+
{
45+
var polyJsonStrings = Shapes.SelectMany(x => x.Polygons).Select(x => x.GetJSON());
46+
return "[" + string.Join(',', polyJsonStrings) + "]";
47+
}
48+
}
49+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Text;
5+
6+
namespace MystifyBlazor.Models
7+
{
8+
/// <summary>
9+
/// A Polygon describes a shape at one instance in time.
10+
/// It has a list of corners and a color.
11+
/// </summary>
12+
public class Polygon
13+
{
14+
public int CornerCount => Corners.Count;
15+
private readonly List<Corner> Corners = new List<Corner>();
16+
public readonly Color Color;
17+
18+
public Polygon(Color color, List<Corner> corners) => (Color, Corners) = (color, corners);
19+
20+
public static Polygon RandomPolygon(Random rand, int cornerCount, double width, double height, Color color) =>
21+
new Polygon(
22+
color: color ?? new Color(rand.NextDouble()),
23+
corners: Enumerable.Range(0, cornerCount).Select(x => Corner.RandomPoint(rand, width, height)).ToList()
24+
);
25+
26+
public Polygon NextPolygon(double delta, double width, double height, bool rainbow)
27+
{
28+
var newCorners = Corners.Select(x => x.NextPoint(delta, width, height)).ToList();
29+
var newColor = rainbow ? new Color(Color.Hue + .01) : Color;
30+
return new Polygon(newColor, newCorners);
31+
}
32+
33+
public string GetJSON()
34+
{
35+
StringBuilder sb = new StringBuilder($"[\"{Color}\"");
36+
foreach (Corner point in Corners)
37+
sb.Append($",[{point.X:0.00},{point.Y:0.00}]");
38+
sb.Append(']');
39+
return sb.ToString();
40+
}
41+
}
42+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Linq;
4+
using System.Threading.Tasks;
5+
6+
namespace MystifyBlazor.Models
7+
{
8+
/// <summary>
9+
/// A shape stores a collection of polygons.
10+
/// Polygons early in the list are historical polygons.
11+
/// The last polygon in the list is the most recent.
12+
/// </summary>
13+
public class Shape
14+
{
15+
public List<Polygon> Polygons = new List<Polygon>();
16+
17+
public Shape(Random rand, int cornerCount, double width, double height, Color color) =>
18+
Polygons.Add(Polygon.RandomPolygon(rand, cornerCount, width, height, color));
19+
20+
public void Advance(double delta, double width, double height, int historyCount, bool rainbow)
21+
{
22+
Polygon nextPolygon = Polygons.Last().NextPolygon(delta, width, height, rainbow);
23+
Polygons.Add(nextPolygon);
24+
while (Polygons.Count > historyCount)
25+
Polygons.RemoveAt(0);
26+
}
27+
}
28+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
<Project Sdk="Microsoft.NET.Sdk.BlazorWebAssembly">
2+
3+
<PropertyGroup>
4+
<TargetFramework>net5.0</TargetFramework>
5+
</PropertyGroup>
6+
7+
<ItemGroup>
8+
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly" Version="5.0.1" />
9+
<PackageReference Include="Microsoft.AspNetCore.Components.WebAssembly.DevServer" Version="5.0.1" PrivateAssets="all" />
10+
<PackageReference Include="Microsoft.AspNetCore.WebUtilities" Version="2.2.0" />
11+
<PackageReference Include="System.Net.Http.Json" Version="5.0.0" />
12+
</ItemGroup>
13+
14+
</Project>
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
2+
Microsoft Visual Studio Solution File, Format Version 12.00
3+
# Visual Studio Version 16
4+
VisualStudioVersion = 16.0.30804.86
5+
MinimumVisualStudioVersion = 10.0.40219.1
6+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MystifyBlazor", "MystifyBlazor.csproj", "{92A1A4F7-1B26-4F7C-95D2-10DFFA70EEDD}"
7+
EndProject
8+
Global
9+
GlobalSection(SolutionConfigurationPlatforms) = preSolution
10+
Debug|Any CPU = Debug|Any CPU
11+
Release|Any CPU = Release|Any CPU
12+
EndGlobalSection
13+
GlobalSection(ProjectConfigurationPlatforms) = postSolution
14+
{92A1A4F7-1B26-4F7C-95D2-10DFFA70EEDD}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
15+
{92A1A4F7-1B26-4F7C-95D2-10DFFA70EEDD}.Debug|Any CPU.Build.0 = Debug|Any CPU
16+
{92A1A4F7-1B26-4F7C-95D2-10DFFA70EEDD}.Release|Any CPU.ActiveCfg = Release|Any CPU
17+
{92A1A4F7-1B26-4F7C-95D2-10DFFA70EEDD}.Release|Any CPU.Build.0 = Release|Any CPU
18+
EndGlobalSection
19+
GlobalSection(SolutionProperties) = preSolution
20+
HideSolutionNode = FALSE
21+
EndGlobalSection
22+
GlobalSection(ExtensibilityGlobals) = postSolution
23+
SolutionGuid = {98A3307D-1B7D-49E9-876B-3B95BD969747}
24+
EndGlobalSection
25+
EndGlobal
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
@page "/"
2+
@using System.Text;
3+
@inject IJSRuntime JsRuntime
4+
@inject NavigationManager NavManager
5+
@using Microsoft.AspNetCore.WebUtilities
6+
7+
<div class="container mt-3">
8+
<div class="display-4">Mystify your Browser with Blazor</div>
9+
10+
<div>
11+
<div class="bg-white shadow mt-3" id="myCanvasHolder">
12+
<canvas id="myCanvas" style="background-color: black;"></canvas>
13+
</div>
14+
15+
<div class="display-5 mt-5">
16+
Configuration
17+
</div>
18+
19+
<div class="d-inline-block m-4">
20+
<label for="Speed">Speed: @MystifyField.Speed</label>
21+
<input type="range" class="form-range" id="Speed"
22+
@bind="MystifyField.Speed" @bind:event="oninput">
23+
</div>
24+
25+
<div class="d-inline-block m-4">
26+
<label for="ShapeCount">Shapes: @MystifyField.ShapeCount</label>
27+
<input type="range" class="form-range" id="ShapeCount"
28+
@bind="MystifyField.ShapeCount" @bind:event="oninput" min="1" max="20">
29+
</div>
30+
31+
<div class="d-inline-block m-4">
32+
<label for="CornerCount">Corners: @MystifyField.CornerCount</label>
33+
<input type="range" class="form-range" id="CornerCount"
34+
@bind="MystifyField.CornerCount" @bind:event="oninput" min="3" max="20">
35+
</div>
36+
37+
<div class="d-inline-block m-4">
38+
<label for="historyCount">History: @MystifyField.HistoryCount</label>
39+
<input type="range" class="form-range" id="historyCount"
40+
@bind="MystifyField.HistoryCount" @bind:event="oninput" min="1" max="50">
41+
</div>
42+
</div>
43+
44+
<div>
45+
<div class="d-inline-block m-4">
46+
<button class="btn btn-primary" @onclick="MystifyField.RandomizeColors">Random Colors</button>
47+
</div>
48+
49+
<div class="d-inline-block m-4">
50+
<input class="form-check-input" type="checkbox" value="" id="rainbow" @bind="MystifyField.Rainbow">
51+
<label class="form-check-label" for="rainbow">
52+
Rainbow
53+
</label>
54+
</div>
55+
</div>
56+
57+
58+
59+
60+
61+
62+
63+
64+
<div class="display-5 mt-3">
65+
Source Code
66+
</div>
67+
<div>
68+
<ul class="py-2">
69+
<li class="my-2">GitHub</li>
70+
<li class="my-2">Blog Post</li>
71+
</ul>
72+
</div>
73+
74+
<div class="text-muted"><small>Running on .NET @Environment.Version</small></div>
75+
</div>
76+
77+
@code
78+
{
79+
Models.Field MystifyField = new Models.Field();
80+
81+
protected override void OnInitialized()
82+
{
83+
JsRuntime.InvokeAsync<object>("initRenderJS", DotNetObjectReference.Create(this));
84+
}
85+
86+
[JSInvokable]
87+
public string UpdateModel(double width, double height)
88+
{
89+
MystifyField.Advance(width, height);
90+
return MystifyField.GetJSON();
91+
}
92+
}

0 commit comments

Comments
 (0)