ساخت ربات تلگرامی با #C
استفاده از چند فرم در کنار هم در ASP.NET MVC
در مثال بالا نیازی به استفاده از Html.Action و child action نبوده. از Html.Action زمانی استفاده میشه که قراره چند partial view از پیش مقدار دهی شده در صفحه، از منابع داده مختلفی مقدار دهی بشن. مثلا قراره در کنار صفحه، از یک منبع داده، آمار سایت رو نمایش بدید (اطلاعات از پیش مقدار دهی شده) و از یک منبع دیگه، لیست مطالب و این دو مورد هم قراره در layout سایت قرار بگیرن. اینجا شما ویرایش اطلاعات رو که ندارید (برای مقدار دهی عناصر فرم از قبل). فقط قراره از کاربر اطلاعات بگیرید. بنابراین استفاده از رندر کردن پارشال مثل قبل کار میکنه. مهم هم نیست که هر پارشالی مدل مختلفی داره. برای ارسال اطلاعات فرم به سرور، فقط نام کنترلها مهم است و نه نوع مدل شما. پروتکل HTTP چیزی از نوع مدل نمیدونه. ASP.NET MVC هست که نامها رو میگیره و متصل میکنه به خواص یک شیء.
در کل مثال بالا برای حالت قرار دادن این فرمها در layout سایت برای تمام صفحات طراحی شده. اگر یک صفحه معمولی و view معمولی هست، در ASP.NET MVC مجاز هستید n تا فرم در صفحه قرار بدید. برای اینکار نیازی به Html.Action نیست؛ با رندر پارشال هم کار میکنه. برای تامین داده اونها هم از ViewModel استفاده کنید. این ViewModel یک خاصیتش، کل اطلاعات فرم یک هست و خاصیت دومش کل اطلاعات فرم 2 و الی آخر.
به تصویر زیر نگاه کنید:
به طور خلاصه کل کار برای ساخت arrow کلاسی به صورت زیر هستش:
ابتدا خاصیت border برای یک مقدار اولیه با رنگ transparent مقدارهی شده و سپس مقدار border-top-color با ccc# مقداردهی شده و حتما عرض و طول باید با 0 مقداردهی بشن تا کادر اضافی حذف بشه،به این صورت:.arrow{ width:0; height:0; border:10px solid transparent; border-top-color:#ccc; }
مقدمات:
-حالا که دونستیم Arrowها چطور ایجاد میشن،این سوال پیش میاد که چطور از این Arrorwها در ساخت tooltipها میشه استفاده کرد؟
CSS به ما این اجازه رو میده که با استفاده از خاصیت content محتوا ایجاد کنیم،البته نه هر محتوایی!،و چیزی که جالبه میتونیم دقیقا مثل یه عنصر باهاش رفتار کنیم و بهش استایل مورد نظر بدیم.
-خاصیت content رو فقط میشه با انتخابگرهای after و before به کار برد.
***نکتهی بسیار بسیار بسیار مهم و حیاتی در طراحی:***
اگه به خاصیت position عنصری مقدار relative داده بشه و در داخل این عنصر،عنصری(فرزند) با خاصیت position برابر absolute ایجاد کنیم،عنصر پدر به عنوان مبدا مختصات برای عنصر فرزند عمل میکنه.(این نکته خیلی از جاها حلال مشکلات برای من بوده!)
خب حالا بریم سر موضوع اصلی،ابتدا استایل زیر رو به container مورد نظر میدیم:
#demo { background-color: #333; height: 100px; position: relative; width: 100px; }
حالا استایل پایه رو برای ایجاد Arrow برای این container ایجاد میکنیم:
#demo:after { content: ' '; height: 0; position: absolute; width: 0; }
1-ما فقط یک space به عنوان محتوا به این استایل دادیم،در واقع همینم کافیه چون ما فقط میخوایم یه بهانه داشته باشیم که با استایل دادن بهش به هدف برسیم،اگه content رو اصلا قید نکنیم،هر استایلی که ایجا بشه نادیده گرفته میشه چون نمیشه هوا رو رنگ آمیزی کرد!
2-ما خاصیت position این عنصر رو به absolute ست کردیم،پس میتونیم این عنصر رو نسبت به container جابجا کنیم.
حالا به عنصر استایل Arrow رو میدیم:
#demo:after { content: ' '; height: 0; position: absolute; width: 0; border: 10px solid transparent; border-top-color: #333; }
حالا که Arrow رو ایجاد کردیم و بعد از عنصر اصلی قرار دادیم،میخوایم یکم جابجاش کنیم تا به نتیجه مورد نظر برسیم:
#demo:after { content: ' '; height: 0; position: absolute; width: 0; border: 10px solid transparent; border-top-color: #333; top: 100%; left: 10px; }
نتیجه نهایی تا اینجای کار
- لیستی از حقوق کارکنان را داریم. در گزارش نهایی آن نیاز است عدد حقوق کارکنانی با مبلغ کمتر از 1000، با رنگی دیگر نمایش داده شوند.
همچنین در این گزارش هر ردیفی که در ماه 7 واقع شده نیز ظاهر عدد سلول مربوط به آن ماه، به رنگ قهوهای و زمینه زرد تغییر یابد.
- در ستون مشخصات افراد این گزارش، نیاز است تصویر کارمند به همراه نام او در ذیل این تصویر (داخل یک سلول) نمایش داده شوند.
چیزی شبیه به این گزارش!
مورد اول در گزارشات، اصطلاحا به conditional formatting معروف است و مورد دوم مرتبط است به تهیه قالبهای سفارشی، بجای استفاده از قالبهای سلولهای پیش فرض PdfReport؛ که در ادامه نحوه انجام این موارد را بررسی خواهیم کرد.
ابتدا سورس کامل این مثال را ملاحظه نمائید:
using System; using iTextSharp.text; using PdfRpt.Core.Contracts; using PdfRpt.Core.Helper; using PdfRpt.FluentInterface; namespace PdfReportSamples.CustomCellTemplate { public class CustomCellTemplatePdfReport { public IPdfReportData CreatePdfReport() { return new PdfReport().DocumentPreferences(doc => { doc.RunDirection(PdfRunDirection.RightToLeft); doc.Orientation(PageOrientation.Portrait); doc.PageSize(PdfPageSize.A4); doc.DocumentMetadata(new DocumentMetadata { Author = "Vahid", Application = "PdfRpt", Keywords = "Test", Subject = "Test Rpt", Title = "Test" }); doc.Compression(new CompressionSettings { CompressionLevel = CompressionLevel.BestCompression, EnableCompression = true }); }) .DefaultFonts(fonts => { fonts.Path(AppPath.ApplicationPath + "\\fonts\\irsans.ttf", Environment.GetEnvironmentVariable("SystemRoot") + "\\fonts\\verdana.ttf"); }) .PagesFooter(footer => { footer.DefaultFooter(DateTime.Now.ToString("MM/dd/yyyy")); }) .PagesHeader(header => { header.DefaultHeader(defaultHeader => { defaultHeader.ImagePath(AppPath.ApplicationPath + "\\Images\\01.png"); defaultHeader.Message("گزارش جدید ما"); }); }) .MainTableTemplate(template => { template.BasicTemplate(BasicTemplate.SnowyPineTemplate); }) .MainTablePreferences(table => { table.ColumnsWidthsType(TableColumnWidthType.Relative); table.MultipleColumnsPerPage(new MultipleColumnsPerPage { ColumnsGap = 20, ColumnsPerPage = 2, ColumnsWidth = 250, IsRightToLeft = true, TopMargin = 7 }); }) .MainTableDataSource(dataSource => { var table = new System.Data.DataTable("لیست حقوق"); table.Columns.Add("شخص", typeof(string)); table.Columns.Add("ماه", typeof(int)); table.Columns.Add("مبلغ", typeof(decimal)); var rnd = new Random(); for (int i = 0; i < 200; i++) table.Rows.Add("شخص " + i, rnd.Next(1, 12), rnd.Next(400, 2000)); dataSource.DataTable(table); }) .MainTableEvents(events => { events.DataSourceIsEmpty(message: "There is no data available to display."); events.CellCreated(args => { //change the background color of the cell based on the value if (args.RowType == RowType.DataTableRow && args.Cell.RowData.Value != null && args.Cell.RowData.Value is decimal) { if ((decimal)args.Cell.RowData.Value <= 1000) args.Cell.BasicProperties.BackgroundColor = BaseColor.CYAN; } }); }) .MainTableSummarySettings(summary => { summary.OverallSummarySettings("جمع کل"); summary.PageSummarySettings("جمع صفحه"); summary.PreviousPageSummarySettings("نقل از ستون قبل"); }) .MainTableColumns(columns => { columns.AddColumn(column => { column.PropertyName("rowNo"); column.IsRowNumber(true); column.CellsHorizontalAlignment(HorizontalAlignment.Center); column.IsVisible(true); column.Order(0); column.Width(1); column.HeaderCell("ردیف"); }); columns.AddColumn(column => { column.PropertyName("شخص"); column.CellsHorizontalAlignment(HorizontalAlignment.Center); column.IsVisible(true); column.Order(1); column.Width(3); column.HeaderCell("شخص"); column.ColumnItemsTemplate(t => t.CustomTemplate(new MyCustomCellTemplate())); }); columns.AddColumn(column => { column.PropertyName("ماه"); column.CellsHorizontalAlignment(HorizontalAlignment.Center); column.IsVisible(true); column.Order(2); column.Width(2); column.HeaderCell("ماه"); column.ColumnItemsTemplate(template => { template.TextBlock(); template.ConditionalFormatFormula(list => { var cellValue = int.Parse(list.GetSafeStringValueOf("ماه", nullValue: "0")); if (cellValue == 7) { return new CellBasicProperties { PdfFontStyle = DocumentFontStyle.Bold | DocumentFontStyle.Underline, FontColor = new BaseColor(System.Drawing.Color.Brown), BackgroundColor = new BaseColor(System.Drawing.Color.Yellow) }; } return new CellBasicProperties { PdfFontStyle = DocumentFontStyle.Normal }; }); }); }); columns.AddColumn(column => { column.PropertyName("مبلغ"); column.CellsHorizontalAlignment(HorizontalAlignment.Center); column.IsVisible(true); column.Order(3); column.Width(2); column.HeaderCell("مبلغ"); column.ColumnItemsTemplate(template => { template.TextBlock(); template.DisplayFormatFormula(obj => obj == null ? string.Empty : string.Format("{0:n0}", obj)); }); column.AggregateFunction(aggregateFunction => { aggregateFunction.NumericAggregateFunction(AggregateFunction.Sum); aggregateFunction.DisplayFormatFormula(obj => obj == null ? string.Empty : string.Format("{0:n0}", obj)); }); }); }) .Export(export => { export.ToXml(); export.ToExcel(); }) .Generate(data => data.AsPdfFile(AppPath.ApplicationPath + "\\Pdf\\RptDataTableSample.pdf")); } } }
using System; using System.Collections.Generic; using iTextSharp.text; using iTextSharp.text.pdf; using PdfRpt.Core.Contracts; using PdfRpt.Core.Helper; namespace PdfReportSamples.CustomCellTemplate { public class MyCustomCellTemplate : IColumnItemsTemplate { Random _rnd = new Random(); public void CellRendered(PdfPCell cell, Rectangle position, PdfContentByte[] canvases, CellAttributes attributes) { } public CellBasicProperties BasicProperties { set; get; } public Func<IList<CellData>, CellBasicProperties> ConditionalFormatFormula { set; get; } public PdfPCell RenderingCell(CellAttributes attributes) { var pdfCell = new PdfPCell(); var table = new PdfPTable(1) { RunDirection = PdfWriter.RUN_DIRECTION_RTL }; var filePath = AppPath.ApplicationPath + "\\Images\\" + _rnd.Next(1, 5).ToString("00") + ".png"; var photo = PdfImageHelper.GetITextSharpImageFromImageFile(filePath); table.AddCell(new PdfPCell(photo, fit: false) { Border = 0, VerticalAlignment = Element.ALIGN_BOTTOM, HorizontalAlignment = Element.ALIGN_CENTER }); var name = attributes.RowData.TableRowData.GetSafeStringValueOf("شخص"); table.AddCell(new PdfPCell(attributes.BasicProperties.PdfFont.FontSelector.Process(name)) { Border = 0, HorizontalAlignment = Element.ALIGN_CENTER }); pdfCell.AddElement(table); return pdfCell; } } }
توضیحات:
- در این مثال از منبع دادهای از نوع DataTable استفاده شده است؛ که نحوه بکارگیری آنرا در متد MainTableDataSource ملاحظه میکنید. ستونهای تعریف شده در MainTableColumns نیز بر اساس ستونهای DataTable مشخص شدهاند.
- در متد DocumentPreferences، نحوه مشخص سازی فشرده سازی نهایی فایل PDF را ملاحظه میکنید. این مورد از مزایای استفاده از فایلهای PDF است.
- برای اعمال فرمت شرطی اطلاعات در PdfReport دو روش وجود دارد.
الف) استفاده از متد MainTableEvents و کار کردن با رخدادهای تعریف شده در آن مانند CellCreated. در اینجا میتوان در نحوه رندر شدن یک سلول دخالت کرد:
events.CellCreated(args => { //change the background color of the cell based on the value if (args.RowType == RowType.DataTableRow && args.Cell.RowData.Value != null && args.Cell.RowData.Value is decimal) { if ((decimal)args.Cell.RowData.Value <= 1000) args.Cell.BasicProperties.BackgroundColor = BaseColor.CYAN; } });
ب) همانطور که در قسمت تعریف ستون «ماه» ملاحظه میکنید، توسط متد template.ConditionalFormatFormula نیز، امکان فرمت شرطی اطلاعات فراهم شده است. در اینجا میتوان به لیست اطلاعات سلولهای ردیف جاری دسترسی یافت و سپس بر اساس آن تصمیم گیری کرد.
- جهت تعریف قالبهای سفارشی سلولها کافی است اینترفیس IColumnItemsTemplate را پیاده سازی کنیم؛ که نمونهای از آن را در کدهای MyCustomCellTemplate فوق ملاحظه میکنید. در اینجا فرصت خواهید داشت هر شکل و طرح متنوعی را تهیه کرده و به صورت یک PdfPCell بازگشت دهید. برای نمونه در مثال فوق، یک جدول را در سلول تعریف شده قرار دادهایم. این جدول یک ستون دارد و هر سلولی که به آن اضافه خواهد شد، یک ردیف را تشکیل خواهد داد. در ردیف اول آن تصویر قرار گرفته و در ردیف دوم آن مقدار سلول جاری.
@Number @code { [Parameter] public string Number { get; set; } protected override Task OnInitializedAsync() { var persianDic = new Dictionary<char, char> { {'0','۰'}, {'1','۱'}, {'2','۲'}, {'3','۳'}, {'4','۴'}, {'5','۵'}, {'6','۶'}, {'7','۷'}, {'8','۸'}, {'9','۹'}, }; var number = Number.ToString(); var ech = number.ToCharArray(); for (int i = 0; i < ech.Length; i++) { persianDic.TryGetValue(ech[i], out char pch); if (pch == null) continue; ech[i] = pch; } Number = new string(ech); return base.OnInitializedAsync(); } }
... @foreach (var item in _items) { <tr> <td class="h6 text-color-1">@item.Title</td> <td> <PersianNumber Number="@item.Price.ToString()"/> ریال</td> </tr> } ...
طراحی و پیاده سازی زیرساختی برای مدیریت خطاهای حاصل از Business Rule Validationها در ServiceLayer
return _customerRepository.GetById(id) .ToResult("Customer with such Id is not found: " + id) .Ensure(customer => customer.CanBePromoted(), "The customer has the highest status possible") .OnSuccess(customer => customer.Promote()) .OnSuccess(customer => _emailGateway.SendPromotionNotification(customer.PrimaryEmail, customer.Status)) .OnBoth(result => result.IsSuccess ? Ok() : Error(result.Error));
تغییر نوع DbContext برنامه
پیش از شروع به یکپارچه کردن ASP.NET Core Identity با برنامهی جاری، نیاز است نوع DbContext آنرا به صورت زیر تغییر داد:
using BlazorServer.Entities; using Microsoft.AspNetCore.Identity.EntityFrameworkCore; using Microsoft.EntityFrameworkCore; namespace BlazorServer.DataAccess { public class ApplicationDbContext : IdentityDbContext { // ...
- این تغییر، نیاز به نصب بستهی نیوگت Microsoft.AspNetCore.Identity.EntityFrameworkCore را نیز در پروژهی جاری دارد تا IdentityDbContext آن شناسایی شده و قابل استفاده شود.
نصب ابزار تولید کدهای ASP.NET Core Identity
اگر از ویژوال استودیوی کامل استفاده میکنید، گزینهی افزودن کدهای ASP.NET Core Identity به صورت زیر قابل دسترسی است:
project -> right-click > Add > New Scaffolded Item -> select Identity > Add
dotnet tool install -g dotnet-aspnet-codegenerator
dotnet add package Microsoft.VisualStudio.Web.CodeGeneration.Design dotnet add package Microsoft.EntityFrameworkCore.Design dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore dotnet add package Microsoft.AspNetCore.Identity.UI dotnet add package Microsoft.EntityFrameworkCore.SqlServer dotnet add package Microsoft.EntityFrameworkCore.Tools
dotnet aspnet-codegenerator identity --dbContext BlazorServer.DataAccess.ApplicationDbContext --force
حال اگر به پروژه دقت کنیم، پوشهی جدید Areas که به همراه فایلهای مدیریتی ASP.NET Core Identity است، اضافه شده و حاوی کدهای صفحات لاگین، ثبت نام کاربر و غیره است.
اعمال تغییرات ابتدایی مورد نیاز جهت استفاده از ASP.NET Core Identity
تا اینجا کدهای پیشفرض مدیریتی ASP.NET Core Identity را به پروژه اضافه کردیم. در ادامه نیاز است تغییرات ذیل را به پروژهی اصلی Blazor Server اعمال کنیم تا بتوان از این فایلها استفاده کرد:
- به فایل BlazorServer.App\Startup.cs مراجعه کرده و UseAuthentication و UseAuthorization را دقیقا در محلی که مشاهده میکنید، اضافه میکنیم. همچنین در اینجا نیاز است مسیریابیهای razor pages را نیز فعال کرد.
namespace BlazorServer.App { public class Startup { // ... public void Configure(IApplicationBuilder app, IWebHostEnvironment env) { // ... app.UseRouting(); app.UseAuthentication(); app.UseAuthorization(); app.UseEndpoints(endpoints => { endpoints.MapRazorPages(); // ... }); } } }
dotnet tool update --global dotnet-ef --version 5.0.4 dotnet build dotnet ef migrations --startup-project ../BlazorServer.App/ add AddIdentity --context ApplicationDbContext dotnet ef --startup-project ../BlazorServer.App/ database update --context ApplicationDbContext
افزودن گزینهی منوی لاگین به برنامهی Blazor Server
پس از این تغییرات، به برنامهای رسیدهایم که مدیریت قسمت Identity آن، توسط قالب استاندارد مایکروسافت که در پوشهی Areas\Identity\Pages\Account نصب شده و بر اساس فناوری ASP.NET Core Razor Pages کار میکند، انجام میشود.
اکنون میخواهیم در منوی برنامهی Blazor Server خود که با صفحات Identity یکی شدهاست، لینکی را به صفحهی لاگین این Area اضافه کنیم. اگر به فایل Shared\MainLayout.razor آن مراجعه کنیم، به صورت پیشفرض، لینکی به صفحهی About، قرار دارد. به همین جهت این مورد را به صورت زیر اصلاح میکنیم:
ابتدا کامپوننت جدید BlazorServer.App\Shared\LoginDisplay.razor را با محتوای زیر ایجاد میکنیم:
<a href="Identity/Account/Register">Register</a> <a href="Identity/Account/Login">Login</a> @code { }
سپس از این کامپوننت در فایل BlazorServer.App\Shared\MainLayout.razor استفاده میکنیم:
<div class="top-row px-4"> <LoginDisplay></LoginDisplay> <a href="https://docs.microsoft.com/aspnet/" target="_blank">About</a> </div>
ثبت و فعالسازی سرویسهای کار با ASP.NET Core Identity
البته اگر در این حال برنامه را اجرا کنیم، با کلیک بر روی لینکهای فوق، استثنائی را مانند یافت نشدن سرویس UserManager، مشاهده خواهیم کرد. برای رفع این مشکل، به فایل BlazorServer.App\Startup.cs مراجعه کرده و سرویسهای Identity را ثبت میکنیم:
namespace BlazorServer.App { public class Startup { // ... public void ConfigureServices(IServiceCollection services) { // ... services.AddIdentity<IdentityUser, IdentityRole>() .AddEntityFrameworkStores<ApplicationDbContext>() .AddDefaultTokenProviders() .AddDefaultUI(); // ...
همانطور که مشاهده میکنید، قالب این قسمت Identity، با قالب قسمت Blazor Server یکی نیست؛ چون توسط Razor Pages و Area آن تامین میشود که master page خاص خودش را دارد. زمانیکه قالب Identity را اضافه میکنیم، علاوه بر Area خاص خودش، پوشهی جدید Pages\Shared را نیز ایجاد میکند که قالب صفحات Identity را به کمک فایل Pages\Shared\_Layout.cshtml تامین میکند:
بنابراین سفارشی سازی قالب این قسمت، شبیه به قالبی که برای کامپوننتهای Blazor مورد استفاده قرار میگیرد، باید در اینجا انجام شود و سفارشی سازی قالب کامپوننتهای Blazor، در پوشهی Shared ای که در ریشهی پروژهاست (BlazorServer.App\Shared\MainLayout.razor) انجام میشود.
کدهای کامل این مطلب را از اینجا میتوانید دریافت کنید: Blazor-5x-Part-21.zip
MTOM در WCF
- Text(Xml) Message Encoder(به صورت پیش فرض در تمام Http-Base Bindingها از این Encoder استفاده میشود)
- Binary Message Encoder(به صورت پیش فرض در تمام Net* Bindingها از این encoder استفاده میشود که برای سرویسهای وب مناسب نیست)
- MTOM Message Encoder (در حالت استفاده از Http-Base Bindingها و انتقال اطلاعات به صورت باینری از این گزینه استفاده میشود که به صورت پیش فرض غیر فعال است)
»خاصیتی که نوع آن آرایه ای از بایتها است نباید دارای DataMemberAttribute باشد؛ بلکه به جای آن باید از MessageBodyMember استفاده نمایید.
»به جای []Byte میتوان از نوع Stream نیز استفاده کرد(الزامی نیست).
»مقدار خاصیت MessageEncoding در Binding استفاده شده باید MTOM تعیین شود.
ابتدا کلاس مورد نظر را به صورت زیر تهیه میکنیم:
[MessageContract] public class MyFile { [MessageHeader] public String Filename { get; set; } [MessageBodyMember] public Byte[] Contents { get; set; } }
- به جای DataContract از MessageContract استفاده میشود؛
- تمام خاصیت هایی که نوع آنها غیر از []Byte است باید دارای MessageHeader باشند؛
- خاصیتی که برای انتقال محتوای باینری تهیه شده است، باید از MessageBodyMember استفاده نماید؛
- مجاز به تعریف فیلد یا فیلد هایی که نوع آنها Primitive Type است نمیباشید.
تنظیمات مربوط به Binding نیز به صورت خواهد بود:
<bindings> <wsHttpBinding> <binding name="WsHttpMtomBinding" messageEncoding="Mtom" /> </wsHttpBinding> </bindings>
هدف از استفاده از MTOM برای افزایش کارایی انتقال دادههای باینری در حجم زیاد است. در زیر نتایج مقایسه بررسی انتقال اطلاعات به دو صورت MTOM و Text برای حجم دادههای متفاوت را مشاهده میکنید:
با دقت در نتایج بالا مشخص میشود که این روش در حجم دادههای پایین (مثل 100 بایت یا 1000 بایت) عملکرد مورد انتظار را نخواهد داشت. پس این نکته را نیز در هنگام پیاده سازی به این روش مد نظر داشته باشید.
<div id="app"> <div><video #video id="video" width="640" height="480" autoplay></video></div> <div><button id="snap" (click)="capture()">ضبط تصویر</button></div> <canvas #canvas id="canvas" width="640" height="480"></canvas> <ul> <li *ngFor="let capture of captures"> <img src="{{ capture }}" height="50" /> </li> </ul> </div>
export class AppComponent implements OnInit, AfterViewInit { @ViewChild('video') public video: ElementRef; @ViewChild('canvas') public canvas: ElementRef; public captures: Array<any>; public constructor() { this.captures = []; } public ngOnInit() { } public capture() { this.canvas.nativeElement.getContext('2d').drawImage(this.video.nativeElement, 0, 0, 640, 480); this.captures.push(this.canvas.nativeElement.toDataURL('image/png')); } public ngAfterViewInit() { if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { navigator.mediaDevices.getUserMedia({ video: true }).then(stream => { this.video.nativeElement.src = window.URL.createObjectURL(stream); this.video.nativeElement.play(); }); } } }
توضیحات :
با استفاده از local variable هایی که در کدهای HTML تعریف کردیم و ViewChild@، میتوانیم المنتها را در متغیرها، load کنیم. در این حالت این امکان وجود دارد تا المنتهای DOM را دستکاری کنیم.public ngAfterViewInit() { if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { navigator.mediaDevices.getUserMedia({ video: true }).then(stream => { this.video.nativeElement.src = window.URL.createObjectURL(stream); this.video.nativeElement.play(); }); } }
- MediaDevices : این اینترفیس دستیابی به دستگاههای ورودی متصل شده، مثلا دوربین، میکروفن و ... را فراهم میسازد.
- MediaDevices.getUserMedia: با گرفتن مجوزی از کاربر از طریق یک هشدار، دوربین کاربر را روشن میکند و هم چنین این متد یک promise را بازگشت میدهد؛ در صورتیکه کاربر اجازه دسترسی بدهد.
- URL.createObjectURL: یک URL را برای یک BLOB مشخص شده ایجاد میکند ( BLOB: Binary large object ) که میتواند به متدی که انتظار یک URL را دارد، پاس داده شود. بعد از برگشت URL، متد ()revokeObjectURL فراخوانی میشود که کارش آزاد سازی منابع مرتبط با url ایجاد شدهی توسط createObjectURL میباشد. در ضمن طول عمر url ایجاد شده برابر با بستن سند (document) در پنجرهای (window) که در آن ایجاد شدهاست، میباشد.
public capture() { this.canvas.nativeElement.getContext('2d').drawImage(this.video.nativeElement, 0, 0, 640, 480); this.captures.push(this.canvas.nativeElement.toDataURL('image/png')); }
- ()getContext : این متد یک شیء را برگشت میدهد که فراهم کنندهی متدها و خصوصیتها، برای رسم در Canvas میباشد.
- ()drawImage: این متددر Canvas رسم را انجام میدهد و همچنین این متد میتواند بخشهایی از یک تصویر را رسم کند یا سایز یک تصویر را افزایش یا کاهش دهد.
- () toDataURL: این متد یک data URI را بازگشت میدهد که یک تصویر در فرمت مشخص شده را بر اساس پارامتر type، برگشت میدهد (پیش فرض آن png میباشد).