C#-Blazor-在线读取测序ABI文件并绘制峰图-代码实现

时间:2024-12-18 06:58:39

前端(razor)

放在项目根目录下的Pages文件夹中。

@page "/ab1"

@using BlazorApp1.Data
@inject Ab1Service aService

@inject IJSRuntime JsRuntime
@inject IWebHostEnvironment Environ

@using System.Text.RegularExpressions;


<PageTitle>Ab1</PageTitle>

<div class="container-fluid p-5">
    <div class="row" style="margin-top:1%;">
        <div>
            <label>
                提示信息:@Message
            </label>
        </div>
        <br/>
        <div>
            输入中心点:<input class="input-group-text" type="text" @bind-value="@targetPos" />
        </div>
        <br />
        <div>

            <label>

                选择上传文件:<InputFile OnChange="@LoadFiles" multiple />

            </label>

            @if (isLoading)
            {
                <p>文件上传中......</p>
            }
            else
            {
                <ul>
                    @foreach (var file in loadedFiles)
                    {
                        <li>
                            <ul>
                                <li class="full-width">文件名:@file.Name</li>
                                <li>最后修改时间:@file.LastModified.ToString()</li>
                                <li>文件大小(byte):@file.Size</li>
                                <li>文件类型:@file.ContentType</li>
                            </ul>
                        </li>

                    }

                </ul>
            }


        </div>

    </div>



    <div id="exportBtnDiv" style="display:none">
        <button value="" class="btn btn-primary" id="ExportSvgBtn" @onclick="ExportSvg" data-toggle="tooltip" title="导出图像">
            导出图像
        </button>
    </div>

    <div class="row" style="display:flex; justify-content:center; align-items:center; width:100%; height:100%;">
        @if (ab1 != null)
        {
            <svg id="mySvg" height="160" width="@ab1.max_width" xmlns="http://www.w3.org/2000/svg" style="display:none;padding:0;margin:0">
                <rect id="myRect" width="@ab1.max_width" height="160" fill="white" style="margin:0" />
                @if (ab1.ya != null && ab1.ya.Length > 0)
                {
                    <path d="@ab1.ya" stroke="green" fill="none" stroke-width="@ab1.line_width" />
                    <path d="@ab1.yc" stroke="blue" fill="none" stroke-width="@ab1.line_width" />
                    <path d="@ab1.yg" stroke="black" fill="none" stroke-width="@ab1.line_width" />
                    <path d="@ab1.yt" stroke="red" fill="none" stroke-width="@ab1.line_width" />
                }
                @if (ab1.Ab1Chars.Count > 0)
                {
                    @foreach (Ab1Char a in ab1.Ab1Chars)
                    {
                        @if (a.ch == "A")
                        {
                            color = "green";
                        }

                        else if (a.ch == "C")
                        {
                            color = "blue";
                        }
                        else if (a.ch == "G")
                        {
                            color = "black";
                        }
                        else
                        {
                            color = "red";
                        }
                        <g>
                            <!-- y是底端 -->
                            <text x="@a.x" y="30" fill="@color" font-family="Courier New" font-size="20" font-weight="bold">@a.ch</text>
                        </g>
                    }
                }
                <path d="@ab1.ArrowPathData" stroke="red" fill="red" stroke-width="0.5"></path>
            </svg>
        }
        
    </div>


    

</div>

<style>
    .full-width {
        white-space: nowrap; /* 禁止换行 */
        overflow: hidden; /* 隐藏溢出部分 */
        text-overflow: clip; /* 显示完整内容,不显示省略号 */
    }
</style>


<script>
    window.interop = {

    }

    function showSvg() {
        document.getElementById('mySvg').style.display = 'block';
    }

    function hideSvg() {
        document.getElementById('mySvg').style.display = 'none';
    }

    function showExportBtn() {
        document.getElementById('exportBtnDiv').style.display = 'block';
    }

    


</script>

@code {
    private Data.Ab1? ab1;
    private string targetPos = "";

    private IJSObjectReference module;

    private List<IBrowserFile> loadedFiles = new();
    private int maxFileSize = 5 * 1024 * 1024;
    private int maxAllowedFiles = 1;
    private bool isLoading;
    private string Message = string.Empty;

    private string color = "black";

    private async Task LoadFiles(InputFileChangeEventArgs e)
    {
        await JsRuntime.InvokeAsync<object>("hideSvg");
        isLoading = true;
        loadedFiles.Clear();
        foreach (var file in e.GetMultipleFiles(maxAllowedFiles))
        {
            try
            {
                //ModelStateDictionary modelState = new ModelStateDictionary();
                loadedFiles.Add(file);
                //string result = await FileHelpers.ProcessFormFile(file, modelState, Environ, maxFileSize);
                // 存储到本地
                Ab1Obj ab1Obj = await Ab1Service.ProcessFormFile(file, Environ, maxFileSize, int.Parse(targetPos));
                if (ab1Obj != null)
                {
                    Message = "成功";
                    // 更新svg
                    ab1 = await aService.GetAb1Async(ab1Obj);
                    await JsRuntime.InvokeAsync<object>("showSvg");
                    await JsRuntime.InvokeAsync<object>("showExportBtn");
                }
                else
                {
                    Message = "失败";
                }

            }
            catch (Exception ex)
            {
                Message = ex.Message;

            }
        }
        isLoading = false;

       
    }

    protected override async Task OnInitializedAsync()
    {
        ab1 = await aService.GetAb1Async();
        
    }

    protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            //await UpdateRadius();
            module = await JsRuntime.InvokeAsync<IJSObjectReference>("import", "./exportSvg.js");
        }

    }

    private async Task ExportSvg()
    {
        var svgElement = await JsRuntime.InvokeAsync<IJSObjectReference>("document.getElementById", "mySvg");
        await module.InvokeVoidAsync("exportSvgToImage2", svgElement, "png", ab1.max_width);
    }

}

Ab1Service

放在项目根目录下的Data文件夹中。

using Microsoft.AspNetCore.Components.Forms;

namespace BlazorApp1.Data
{
    public class Ab1Service
    {
        public Task<Ab1> GetAb1Async()
        {
            Ab1 ab1 = new Ab1();
            return Task.FromResult(ab1);
        }

        public Task<Ab1> GetAb1Async(Ab1Obj ab1Obj) {
            Ab1 ab1 = new Ab1();
            double max_width = 0.0;
            List<string> ans = ab1Obj.GetPathData(out max_width);
            ab1.ya = ans[0];
            ab1.yc = ans[1];
            ab1.yg = ans[2];
            ab1.yt = ans[3];
            ab1.max_width = max_width;
            List<Ab1Char> ab1Chars = ab1Obj.GetXPosData();
            ab1.Ab1Chars.AddRange(ab1Chars);
            // 固定值
            ab1.ArrowPathData = ab1Obj.GetArrowData(20);
            
            return Task.FromResult(ab1);
        }

        /// <summary>
        /// 上传的文件存储到:C:\项目根目录\Development\unsafeUploads
        /// </summary>
        /// <param name="formFile"></param>
        /// <param name="envir"></param>
        /// <param name="maxFileSize">前端的文件大小限制,目前是5MB</param>
        /// <returns></returns>
        public static async Task<Ab1Obj> ProcessFormFile(IBrowserFile formFile, IWebHostEnvironment envir, int maxFileSize, int target)
        {
            var path = Path.Combine(envir.ContentRootPath, envir.EnvironmentName, "unsafeUploads", formFile.Name);
            using (
                var reader =
                    new FileStream(
                        path,
                        FileMode.Create))
            {
                await formFile.OpenReadStream(maxFileSize).CopyToAsync(reader);
            }
            // 读取        
            Ab1Obj ab1Obj = new Ab1Obj(path, target);
            return ab1Obj;
        }
    }
}

Ab1Obj和Ab1类

Ab1Obj是解析ab1文件的类,里面包含一些变量和解析相关的函数。这部分受版权保护,恕不公开。

Ab1类的实现是:

namespace BlazorApp1.Data
{
    public class Ab1Char {
        public string ch = "";
        public double x = 0.0;
        public Ab1Char() { }

        public Ab1Char(string ch, double x) {
            this.ch = ch;
            this.x = x;
        }
    }
    
    public class Ab1
    {
        // 记录y值
        public string ya { set; get; } = "";
        public string yc { set; get; } = "";
        public string yg { set; get; } = "";
        public string yt { set; get; } = "";
        public double max_width { set; get; } = 0.0;
        public int line_width { set; get; } = 3;
        public int target { set; get; } = 0;
        // 记录字母的位置
        public List<Ab1Char> Ab1Chars = new List<Ab1Char>();
        // 记录箭头的path数据
        public string ArrowPathData = "";
    }
}