在Blazor服务器端使用HTML Canvas进行绘制






3.48/5 (8投票s)
HTML Canvas 元素支持绘图。本文介绍如何在 Blazor Server-side 中使用它。
引言
Blazor Server-side 是一项基于 .NET Core 的开源技术,支持 Windows、Linux 和 Apple 操作系统。您可以使用 C# 编写所有代码,这是我选择的语言。您可以使用 .NET Core CLR 支持的任何语言。
HTML <canvas>
元素允许您通过 JavaScript 函数对其进行操作来绘图。
将两者结合起来,可以创建一个 Web 页面,您可以在其中在客户端浏览器上的 canvas
元素上进行绘图。
您可以绘制任何您想要的内容。要了解在 JavaScript 中 <canvas>
元素上可以绘制的所有内容,请参阅以下文章:
GitHub 存储库位于:
您根据需要使用的本系列中的其他文章已发布:
要求
安装 Visual Studio 2019 社区版,如果您或您的雇主提供,也可以使用专业版或企业版。在安装 VS 2019 时,您需要勾选 Web 开发部分,以便获得 Blazor Server-side 解决方案模板。
您需要了解基础的 C# 知识。
创建默认的 Blazor Server-Side 解决方案(面向初学者)
打开 Visual Studio 2019,然后单击 创建新项目 按钮。
然后在搜索框中输入 Blazor
。您应该会看到 Blazor 应用模板。确保它是 C# 的。然后选择它,并单击右下角的 下一步 按钮。
然后为项目命名。我选择将我的项目命名为 BlazorCanvasApp
。为解决方案文件指定您希望将其放置在驱动器上的位置。如果您愿意,可以保留默认位置。
请不要像示例那样输入位置,因为这是我自己的驱动器文件夹路径,在您的计算机上不存在。
然后单击右下角的 创建 按钮。
然后选择 Blazor Server App。这将创建一个 Blazor Server-side 应用。单击右下角的 创建 按钮。
然后 Blazor 解决方案将被创建。它包含一些默认代码。所以只需点击 运行 按钮,让它进行构建、编译和运行,它将在您的默认浏览器中启动。
我的默认浏览器是 Windows 10 Pro 上的 Google Chrome。结果如下图所示:
现在将 Nuget 包添加到解决方案中(面向初学者)
在 Visual Studio 2019 的菜单中,选择菜单选项 工具 => NuGet 包管理器 => 管理解决方案的 NuGet 包...
这将弹出窗口,我们在其中将 Blazor.Extensions.Canvas
NuGet 包添加到我们的项目中。
现在,确保您处于 浏览 选项卡。然后在搜索框中,输入 Blazor.Extensions.Canvas
。单击并选择 Blazor.Extensions.Canvas
来选择 NuGet 包。然后在右侧,单击 复选框
以便为项目选择它。然后单击 安装 按钮。等待 NuGet 包安装完成。
以同样的方式,添加 Newtonsoft.Json
NuGet 包。我们将使用它来进行 JavaScript Interop。JSInterop
是一种方法,通过这种方法我们可以从 C# 代码调用 JavaScript 函数。
编写 Canvas 绘图 Razor 组件(面向所有人)
在 Visual Studio 中的右侧窗格中,转到 解决方案资源管理器 窗格。展开 Pages 文件夹节点。右键单击它,然后在弹出菜单中,选择菜单选项 添加 => Razor 组件...
在弹出模态窗口中,为组件命名。我将其命名为 CanvasDrawing.razor
。然后单击 添加 按钮。
在此文件中,粘贴以下代码:
@page "/CanvasDrawing"
@using Blazor.Extensions
@using Blazor.Extensions.Canvas
@using Blazor.Extensions.Canvas.Canvas2D
@using Newtonsoft.Json
@using Newtonsoft.Json.Linq
@inject IJSRuntime jsRuntime
<div @ref="divCanvas" @onclick="OnClick">
<BECanvas @ref="myCanvas" Height="800" Width="800"></BECanvas>
</div>
<h3>CanvasDrawing</h3>
@code {
ElementReference divCanvas;
Blazor.Extensions.BECanvasComponent myCanvas;
Canvas2DContext currentCanvasContext;
class PieChartSlice
{
public string Name { get; set; }
public double PercentageOfSlice { get; set; }
public string ColorOfSlice { get; set; }
public double LabelX { get; set; }
public double LabelY { get; set; }
}
async void OnClick(MouseEventArgs eventArgs)
{
double mouseX = 0;
double mouseY = 0;
List<PieChartSlice> pieChartData = new List<PieChartSlice>();
if (divCanvas.Id?.Length > 0)
{
string data = await jsRuntime.InvokeAsync<string>("getDivCanvasOffsets",
new object[] { divCanvas });
JObject offsets = (JObject)JsonConvert.DeserializeObject(data);
mouseX = eventArgs.ClientX - offsets.Value<double>("offsetLeft");
mouseY = eventArgs.ClientY - offsets.Value<double>("offsetTop");
currentCanvasContext = await myCanvas.CreateCanvas2DAsync();
await currentCanvasContext.ClearRectAsync(0, 0, 800, 800);
await currentCanvasContext.SetFillStyleAsync("Red");
await currentCanvasContext.FillRectAsync(mouseX, mouseY, 5, 5);
await currentCanvasContext.StrokeTextAsync("ClientX: " + mouseX +
" Client Y: " + mouseY, 20, 20);
pieChartData.Add(new PieChartSlice {
Name = "Akshay's Company",
PercentageOfSlice = 50,
ColorOfSlice = "Blue",
LabelX = 287,
LabelY = 459 });
pieChartData.Add(new PieChartSlice {
Name = "John Doe's Company",
PercentageOfSlice = 30,
ColorOfSlice = "Red",
LabelX = 200,
LabelY = 260 });
pieChartData.Add(new PieChartSlice {
Name = "Jane Doe's Company",
PercentageOfSlice = 20,
ColorOfSlice = "Green",
LabelX = 400,
LabelY = 280 });
if (myCanvas != null && currentCanvasContext != null)
{
await currentCanvasContext.SaveAsync();
await currentCanvasContext.SetFillStyleAsync("Black");
await currentCanvasContext.SetFontAsync("15pt Ariel");
await currentCanvasContext.FillTextAsync(
"Widget Industry Market Share Breakup %", 160, 120);
await currentCanvasContext.SetFontAsync("12pt Ariel");
await currentCanvasContext.SetStrokeStyleAsync("Black");
double currangle = 0;
double lastangle = 0;
for (var i = 0; i < pieChartData.Count; i++)
{
currangle += (pieChartData[i].PercentageOfSlice * 360) / 100;
await currentCanvasContext.SetFillStyleAsync(
pieChartData[i].ColorOfSlice);
await currentCanvasContext.BeginPathAsync();
await currentCanvasContext.MoveToAsync(350, 350);
await currentCanvasContext.ArcAsync(350, 350, 200,
(Math.PI / 180) * lastangle,
(Math.PI / 180) * currangle, false);
await currentCanvasContext.ClosePathAsync();
await currentCanvasContext.FillAsync();
await currentCanvasContext.StrokeTextAsync(pieChartData[i].Name,
pieChartData[i].LabelX, pieChartData[i].LabelY);
lastangle = currangle;
}
await currentCanvasContext.RestoreAsync();
}
}
}
}
@page
指令表示 URL 将是基本 URL + /CanvasDrawing。@using
与 C# 的 using
语句相同。@inject
指令将 IJSRuntime
注入到 Razor 组件中。这使我们能够进行 JSInterop。我们可以使用类型为 IJSRuntime
的 jsRuntime
变量来调用我们的 JavaScript 函数,该函数将返回 <div>
的 offsetLeft
和 offsetTop
属性值。然后,这些值将从鼠标单击事件参数中的 ClientX
和 ClientY
中减去,以获取鼠标在 <canvas>
元素内的实际位置。<div>
元素中的 @ref
创建一个 ElementReference
。这被传递给 JavaScript 函数以获取偏移量。BECanvas
是 Blazor.Extensions.Canvas
,它创建一个 <canvas>
元素。@ref
允许我们获取对 <canvas>
元素的引用,以创建 2D 上下文,我们将在 <canvas>
元素上使用该上下文进行绘图。
为什么我用 Div
包裹 Canvas
元素?这是因为在撰写本文时,OnClick
事件不适用于 Canvas
元素。像这样的注意事项有很多,因为 Blazor 是一项新技术。
现在我们需要在 _Host.cshtml 文件中创建 JavaScript 函数 getDivCanvasOffsets
。所以打开这个文件,在最后一个 body 结束标签之前,粘贴以下代码:
<script src="_content/Blazor.Extensions.Canvas/blazor.extensions.canvas.js"></script>
<script>
function getDivCanvasOffsets(el) {
var obj = {};
obj.offsetLeft = el.offsetLeft;
obj.offsetTop = el.offsetTop;
return JSON.stringify(obj);
}
</script>
第一个脚本是用于 Blazor.Extensions.NuGet
包的。它包含 NuGet 包用于 JSInterop 来控制 <canvas>
元素的所有 JavaScript 函数。
现在您可以在 Visual Studio 中运行项目,然后您将进入浏览器中的常规页面。您需要更改 URL 以指向 razor 组件的路由,在我的情况下是 localhost:4046/CanvasDrawing。您可以单击画布,它将在您单击的画布左上角处绘制坐标。在您单击的点,它将绘制一个小的 5x5 像素的红色填充矩形。
下面是一个输出示例:
如果您可以绘制一些文本和 红色
矩形,那么您就可以绘制任何内容。
我建议首先学习 JavaScript 中完整的 Canvas
API。然后意识到,如果 JavaScript API for Canvas
元素中有 MoveTo(x,y)
,那么它在 Blazor.Extensions.Canvas
中的对应项是 MoveToAsync(x,y)
。当然,所有绘图函数都在 Canvas
2D 上下文中,该上下文是从 Canvas
元素派生的。模式遵循 HTML <canvas>
元素的 JavaScript API。有些东西,比如 Gradients,在 Blazor.Extensions.Canvas
中不可用。您必须注意哪些可用。
历史
- 2020 年 6 月 2 日 - 初始版本