نظرات مطالب
شمسی سازی Date-Picker توکار Angular Material 6x
- این پروژه به Angular Material 9x ارتقاء داده شده؛ جزئیات بیشتر
- کتابخانه‌ی jalali-moment متاسفانه باگ زیاد دارد. اگرتنظیم jalaliMoment.locale("fa") در آن وجود نداشته باشد، مدام خطای null reference می‌دهد. همچنین روش معرفی تاریخ میلادی به آن اینبار باید به اینصورت باشد (عدم سازگاری با نگارش‌های قبلی آن).
مطالب
جایگزین کردن jQuery با JavaScript خالص - قسمت سوم - تغییر شیوه‌نامه‌ی المان‌ها
در این قسمت روش جایگزین کردن متد css جی‌کوئری را با کدهای خالص جاوا اسکریپتی بررسی می‌کنیم.

کار با Inline Styles
  <h1>News</h1>
  <div>Welcome to our site!</div>

  <h2>World</h2>

  <h3>Title 1</h3>
  <div>description 1.</div>

  <h2>Science</h2>

  <h3>Title 2</h3>
  <div>description 2.</div>
در این مثال می‌خواهیم با استفاده از جاوا اسکریپت، المان‌های h2 و h3 را یافته و سپس h2ها را آبی و h3ها را سبز کنیم:
  var headings = document.querySelectorAll('h2, h3');
  for (var i = 0; i < headings.length; i++) {
    if (headings[i].tagName === 'H2') {
      headings[i].style.color = 'blue';
    }
    else {
      headings[i].style.color = 'green';
    }
  }
برای تغییر inline style المان‌ها، از خاصیت style آن‌ها استفاده می‌شود که در نهایت این شیوه‌نامه‌های جدید توسط ویژگی style به همان المان اضافه می‌شوند:
<h2 style="color: blue">….</h2>
<h3 style="color: green">….</h3>
خاصیت style جزو استاندارد DOM Level 2 است که در سال 2000 تصویب شده‌است (از زمان IE 8.0 به بعد در دسترس است). باید دقت داشت که از این روش بیشتر در کتابخانه‌های جاوا اسکریپتی برای شرایطی خاص، جهت تغییر پویای رابط کاربری استفاده می‌شود و هر تغییری که در اینجا اعمال شود، مقادیر قبلی موجود را بازنویسی می‌کند.
همچنین اگر بخواهیم به یک المان چندین شیوه‌نامه را انتساب دهیم، روش کار به صورت زیر است:
  <h2>World</h2>

  ...

  <h2>Science</h2>

 <script>
  var headings = document.querySelectorAll('h2');
  for (var i = 0; i < headings.length; i++) {
    headings[i].style.color = 'blue';
    headings[i].style.fontWeight = 'bold';
  }
 </script>
پس از یافتن المان‌های مدنظر، تنها کافی است نام شیوه‌نامه‌ی مدنظر را به خاصیت style اضافه و مقدار دهی کنیم. در اینجا نام شیوه‌نامه‌ای که «کبابی» باشد، مانند font-weight، به صورت camel case مانند fontWeight درج خواهد شد؛ هرچند از همان نام اصلی نیز می‌توان به صورت زیر استفاده کرد:
 headings[i].style['font-weight'] = 'bold';
روش دیگری نیز برای انجام این تغییرات چندتایی وجود دارد:
  var headings = document.querySelectorAll('h2');

  for (var i = 0; i < headings.length; i++) {
    headings[i].style.cssText = 'color: blue; font-weight: bold';
  }
خاصیت style یک المان، از نوع اینترفیس CSSStyleDeclaration است که دارای خاصیت استاندارد cssText نیز می‌باشد. توسط این خاصیت می‌توان چندین شیوه‌نامه را به صورت یکجا به عنصری انتساب داد و یا تمام آن‌ها را خواند.


کار با Style Sheets

Inline styles تنها روش کار با شیوه‌نامه‌ها نیست. روش صحیح و قابل مدیریت کار با شیوه‌نامه‌ها استفاده از فایل‌های style sheets است. برای مثال تغییرات قبل را می‌توان در فایلی به نام styles.css و با محتوای زیر ایجاد کرد:
h2 { color: blue; }
h3 { color: green; }
و سپس آن‌را به صفحه متصل نمود:
 <link href="styles.css" rel="style sheet">
و یا حتی می‌توان این شیوه نامه را به صورت inline نیز به ابتدای صفحه اضافه نمود:
<style>
  h2 { color: blue; }
  h3 { color: green; }
</style>
اما ممکن است در برنامه بخواهیم امکان تغییر پویای قالب را به کاربران بدهیم. در یک چنین حالتی اعمال این نوع شیوه‌نامه‌ها توسط جاوا اسکریپت مفهوم پیدا می‌کند:
var sheet = document.styleSheets[0];
sheet.insertRule('h2 { font-style: italic; }', sheet.cssRules.length - 1);
اولین سطر، اولین تگ style اضافه شده به صفحه را یافته (این style می‌تواند inline و یا لینک شده‌ی توسط یک فایل باشد) و سپس شیوه نامه‌ی جدیدی را توسط متد insertRule، در انتهای آن به صورت پویا درج می‌کند.


مخفی کردن و نمایش دادن المان‌ها در صفحه

جی‌کوئری به همراه متدهای hide و show است که کار مخفی کردن و یا نمایش دادن مجدد یک المان‌را انجام می‌دهند:
// hide an element
$element.hide();

// show it again
$element.show();
در کل روش‌های زیادی برای مخفی کردن یک المان وجود دارند. برای مثال می‌توان opacity آن‌را به صفر تنظیم کرد و یا position آن‌را به absolute و سپس آن‌را در مختصاتی خارج از صفحه قرار داد. اما عموما خاصیت display را به none تنظیم می‌کنند. همچنین در استاندارد W3C HTML5، خاصیت جدید hidden از نوع boolean نیز به المان‌ها اضافه شده‌اند که دقیقا برای همین‌منظور بکار می‌رود. مزیت مهم این خاصیت نه فقط استاندارد بودن آن، بلکه بالابردن دسترسی پذیری المان‌های صفحه توسط برنامه‌های «screen reader» مخصوص معلولین است. بنابراین با استفاده از جاوا اسکریپت خالص برای مخفی کردن یک المان می‌توان نوشت:
element.setAttribute('hidden', '');
این روش 25 بار سریعتر از متد hide جی‌کوئری است! از این جهت که jQuery در پشت صحنه مدام متد window.getComputedStyle را برای موارد خاص و بحرانی کار با شیوه‌نامه‌ها فراخوانی می‌کند (در تمام متدهایی که با CSS کار می‌کنند) و این متد تاثیر منفی بر روی کارآیی برنامه دارد.
و چون خاصیت hidden از نوع Boolean است، ذکر آن در یک المان یعنی تنظیم آن به true و حذف آن، یعنی تنظیم آن به false یا نمایش مجدد المان در اینجا:
element.removeAttribute('hidden');


اندازه‌گیری تاثیر شیوه‌نامه‌ها بر روی طول و عرض المان‌ها

CSS Box Model یک چنین تعریفی را دارد:


زمانیکه از متدهای ()width و ()height جی‌کوئری بر روی المانی استفاده می‌شود، صرفا طول و عرض قسمت «content» را دریافت خواهید کرد.
برای این منظور در جاوا اسکریپت خالص این خواص در اختیار ما است:
<style>
  .box {
    padding: 10px;
    margin: 5px;
    border: 3px solid;
    display: inline-block;
  }
</style>
<span class="box">a box</span>
روش اندازه گیری Content + Padding توسط جاوا اسکریپت خالص:
 // returns 38
var clientHeight = document.querySelector('.box').clientHeight;

// returns 55
var clientWidth = document.querySelector('.box').clientWidth;
این خواص هرچند اخیرا به استانداردهای CSS به صورت رسمی اضافه شده‌اند، اما از زمان IE 6.0 پشتیبانی می‌شده‌اند و با متدهای ()innerWidth و ()innerHeight جی‌کوئری قابل مقایسه هستند.

روش اندازه گیری Content + Padding + Border توسط جاوا اسکریپت خالص:
 // returns 44
var offsetHeight = document.querySelector('.box').offsetHeight;

// returns 61
var offsetWidth = document.querySelector('.box').offsetWidth;
این خواص از زمان IE 8.0 پشتیبانی می‌شده‌اند.
اشتراک‌ها
پروژه Marka

Beautiful icon transformations 

پروژه Marka
مطالب
OpenCVSharp #17
تشخیص اشخاص به کمک OpenCV

فرض کنید قصد دارید یک سیستم حضور غیاب مبتنی بر تشخیص چهره را طراحی کنید. قسمت استخراج چهره، از تصویر کلی رسیده را بررسی کردیم. اما در ادامه چگونه تشخیص دهیم که این چهره متعلق به چه شخصی است؟ با توجه به اینکه تصویر چهره‌ی یک شخص می‌تواند از زوایای مختلفی تهیه شود و یا حتی حالات روحی منعکس شده‌ی در صورت نیز در تغییر بیت و بایت‌های تصویر چهره مؤثر هستند.


بانک اطلاعاتی تصاویر چهره‌های اشخاص

در اینجا از تصاویر «The Database of Faces» استفاده خواهیم کرد. این مجموعه شامل تصاویر 40 شخص، در 10 حالت مختلف است.


برای بارگذاری این تصاویر و استفاده‌ی از آن‌ها در الگوریتم FisherFaceRecognizer نیاز به ساختار ذیل است:
public class ImageInfo
{
    public Mat Image { set; get; }
    public int ImageGroupId { set; get; }
    public int ImageId { set; get; }
}
در اینجا Image، محتوای تصویر انتخابی است. مقدار ImageGroupId مساوی مقدار عددی نام پوشه‌ی تصاویر منهای یک، تنظیم می‌شود. برای مثال پوشه‌ی s1 به گروه صفر تنظیم می‌شود. ImageId نیز به یک مقدار خود افزایش یابنده معادل شماره‌ی جاری تصویر، تنظیم می‌گردد؛ به این صورت:
var images = new List<ImageInfo>();
 
var imageId = 0;
foreach (var dir in new DirectoryInfo(@"..\..\Images").GetDirectories())
{
    var groupId = int.Parse(dir.Name.Replace("s", string.Empty)) - 1;
    foreach (var imageFile in dir.GetFiles("*.pgm"))
    {
        images.Add(new ImageInfo
        {
            Image = new Mat(imageFile.FullName, LoadMode.GrayScale),
            ImageId = imageId++,
            ImageGroupId = groupId
        });
    }
}
ابتدا پوشه‌های دیتابیس تصاویر یافت شده و سپس از نام هر پوشه یک شما‌‌ره‌ی گروه (یا شماره‌ی شخص) استخراج می‌شود. سپس تصاویر این پوشه به لیست تصاویر اصلی اضافه خواهند شد.


تشخیص یک چهره‌ی اتفاقی

پس از تشکیل لیست تصاویر، اکنون کار با الگوریتم FisherFaceRecognizer به نحو ذیل خواهد بود:
var model = FaceRecognizer.CreateFisherFaceRecognizer();
model.Train(images.Select(x => x.Image), images.Select(x => x.ImageGroupId));
 
var rnd = new Random();
var randomImageId = rnd.Next(0, images.Count - 1);
var testSample = images[randomImageId];
 
Console.WriteLine("Actual group: {0}", testSample.ImageGroupId);
Cv2.ImShow("actual", testSample.Image);
 
var predictedGroupId = model.Predict(testSample.Image);
Console.WriteLine("Predicted group: {0}", predictedGroupId);
پارامتر اول متد Train، لیست تصاویر است و پارامتر دوم، لیست شماره گروه‌های متناظر با هر تصویر است که در اینجا به عنوان برچسب نیز نامگذاری شده‌است.
سپس با استفاده از کلاس Random، یک تصویر اتفاقی انتخاب می‌شود.
اکنون این تصویر اتفاقی به متد Predict ارسال شده و نتیجه‌ی آن، شماره گروه چهره‌ی تشخیص داده شده‌است. به این ترتیب می‌توان تشخیص داد که یک تصویر مفروض ورودی، متعلق به چه شخصی (یا در اینجا گروه یا برچسب) است.



کدهای کامل این مثال را از اینجا می‌توانید دریافت کنید.
مطالب
نوشتن TagHelperهای سفارشی برای ASP.NET Core
در مطلب «ارتقاء به ASP.NET Core 1.0 - قسمت 12 - معرفی Tag Helpers» با مفهوم جدید Tag Helpers و همچنین نحوه‌ی استفاده‌ی از نمونه‌های پیش فرض و توکار آن در ASP.NET Core آشنا شدیم. در ادامه قصد داریم با نحوه‌ی پیاده سازی نمونه‌های سفارشی آن‌ها نیز آشنا شویم.


نوشتن یک Tag Helper سفارشی، برای رندر کردن لیست‌های بوت استرپی

فرض کنید می‌خواهیم یک tag helper جدید را جهت رندر کردن لیست بوت استرپی ذیل تهیه کنیم:
<ul class="list-group"> 
  <li class="list-group-item">Item 1</li> 
  <li class="list-group-item">Item 2</li> 
  <li class="list-group-item">Item 3</li> 
</ul>
برای اینکار یک کتابخانه‌ی جدید را به پروژه‌ی جاری اضافه کرده و سپس وابستگی‌های ذیل را نیز به آن اضافه می‌کنیم. این‌ها حداقل‌هایی هستند که جهت دسترسی به امکانات MVC و Tag Helpers، در یک پروژه‌ی مجزای Class library نیاز داریم:
{
  "version": "1.0.0-*",
 
    "dependencies": {
        "NETStandard.Library": "1.6.0",
        "Microsoft.AspNetCore.Http.Extensions": "1.0.0",
        "Microsoft.AspNetCore.Mvc.Abstractions": "1.0.1",
        "Microsoft.AspNetCore.Mvc.Core": "1.0.1",
        "Microsoft.AspNetCore.Mvc.ViewFeatures": "1.0.1",
        "Microsoft.AspNetCore.Razor.Runtime": "1.0.0"
    },
 
  "frameworks": {
    "netstandard1.6": {
      "imports": "dnxcore50"
    }
  }
}


بررسی آناتومی یک کلاس TagHelper

یک کلاس Tag Helper سفارشی، در حالت کلی می‌تواند شکل زیر را داشته باشد:
namespace Core1RtmEmptyTest.TagHelpers
{
    [HtmlTargetElement("list-group")]
    public class ListGroupTagHelper : TagHelper
    {
        [HtmlAttributeName("asp-items")]
        public List<string> Items { get; set; }
 
        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
        }
    }
}
در اینجا نام کلاس، به TagHelper ختم می‌شود و همچنین این کلاس از کلاس پایه‌ی TagHelper ارث بری می‌کند. ذکر HtmlTargetElement الزامی بوده و در صورت عدم تعریف آن، TagHelper تعریف شده توسط ASP.NET Core شناسایی و بارگذاری نخواهد شد.
توسط HtmlTargetElement نام نهایی تگ مرتبط با TagHelper سفارشی را تعریف و سفارشی سازی کرده‌ایم. در این حالت این TagHelper جدید در Viewهای برنامه، توسط تگ ذیل شنایی می‌شود (بجای نام پیش فرض کلاس):
 <list-group></list-group>
همچنین در اینجا، یک خاصیت عمومی نیز تعریف شده‌است. تمام خواص عمومی تعریف شده‌ی در اینجا به صورت ویژگی‌هایی در تگ نهایی TagHelper قابل دسترسی و مقدار دهی خواهند بود:
 <list-group asp-items="Model.Items"></list-group>
 برای لغو این حالت می‌توان از ویژگی HtmlAttributeNotBound استفاده کرد.
برای اینکه نام این ویژگی را نیز بتوانیم سفارشی سازی کنیم، می‌توان از ویژگی HtmlAttributeName استفاده کرد. در صورت عدم ذکر آن، از نام پیش فرض این خاصیت عمومی جهت تعریف ویژگی‌های تگ نهایی استفاده می‌گردد.
عملیات نهایی افزودن تگ‌های HTML، به View برنامه، در متد Process انجام می‌شود. در اینجا توسط متدهایی مانند output.Content.AppendHtml می‌توان خروجی دلخواهی را به صفحه اضافه کرد.


تکمیل کدهای Tag Helper سفارشی رندر کردن لیست‌های بوت استرپی

پس از آشنایی با ساختار کلی یک کلاس TagHelper، اکنون می‌توان کدهای آن را به نحو ذیل تکمیل کرد:
using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using Microsoft.AspNetCore.Razor.TagHelpers;
 
namespace Core1RtmEmptyTest.TagHelpers
{
    [HtmlTargetElement("list-group")]
    public class ListGroupTagHelper : TagHelper
    {
        [HtmlAttributeName("asp-items")]
        public List<string> Items { get; set; }
 
        protected HttpRequest Request => ViewContext.HttpContext.Request;
 
        [ViewContext, HtmlAttributeNotBound]
        public ViewContext ViewContext { get; set; }
        public override void Process(TagHelperContext context, TagHelperOutput output)
        {
            if (context == null)
            {
                throw new ArgumentNullException(nameof(context));
            }
 
            if (output == null)
            {
                throw new ArgumentNullException(nameof(output));
            }
 
            if (Items == null)
            {
                throw new InvalidOperationException($"{nameof(Items)} must be provided");
            }
 
            output.TagName = "ul";
            output.TagMode = TagMode.StartTagAndEndTag;
            output.Attributes.Add("class", "list-group");
 
            foreach (var item in Items)
            {
                TagBuilder itemBuilder = new TagBuilder("li");
                itemBuilder.AddCssClass("list-group-item");
                itemBuilder.InnerHtml.Append(item);
                output.Content.AppendHtml(itemBuilder);
            }
        }
    }
}
توضیحات:
 - چون می‌خواهیم تگ نهایی آن، list-group نام داشته باشد، آن‌را توسط ویژگی HtmlTargetElement به صورت صریحی مشخص کرده‌ایم.
 - همچنین علاقمندیم تا ویژگی دریافت لیست آیتم‌ها، نامی معادل asp-items داشته باشد. بنابراین آن‌را نیز توسط ویژگی HtmlAttributeName، دقیقا مشخص کرده‌ایم.
 - در این کلاس، یک خاصیت اضافه‌ی ViewContext را نیز مشاهده می‌کنید. ویژگی ViewContext اعمالی به آن، سبب خواهد شد تا اطلاعات درخواست جاری، به این خاصیت عمومی، به صورت خودکار تزریق شود. بنابراین اگر نیاز به اطلاعاتی مانند Request جاری دارید، شیء ViewContext.HttpContext.Request، این مقادیر را در اختیار شما قرار می‌دهد. به علاوه اگر دقت کرده باشید، این خاصیت با ویژگی HtmlAttributeNotBound مزین شده‌است. از این جهت که نمی‌خواهیم این خاصیت عمومی، در لیست ویژگی‌های تگ نهایی TagHelper در حال تهیه، ظاهر شود.
 - پس از آن کاری که انجام شده، تکمیل متد Process است. در اینجا توسط output.TagName مشخص می‌کنیم که TagHelper جاری، در بین تگ‌های ul قرار گیرد (مفهوم TagMode.StartTagAndEndTag ذکر شده) و همچنین این تگ محصور کننده دارای کلاس list-group بوت استرپ نیز خواهد بود.
 - سپس بر روی لیست آیتم‌های دریافت شده، یک حلقه را تشکیل داده و به کمک TagBuilder، تگ‌های li داخل ul برونی را تکمیل می‌کنیم. این TagBuilder در نهایت توسط متد output.Content.AppendHtml به View برنامه اضافه خواهد شد. در اینجا، متد Append هم وجود دارد. اگر از آن استفاده شود، خروجی نهایی HTML Encoded خواهد بود.
 

ثبت و استفاده‌ی از TagHelper سفارشی تهیه شده

پس از تعریف TagHelper سفارشی فوق، ابتدا ارجاعی از اسمبلی آن‌را به پروژه‌ی جاری اضافه می‌کنیم و سپس به فایل ViewImports.cshtml_ برنامه مراجعه و یک سطر ذیل را به آن اضافه می‌کنیم:
 @addTagHelper *,Core1RtmEmptyTest.TagHelpers
در اینجا عبارت Core1RtmEmptyTest.TagHelpers همان نام فضای نام اصلی پروژه‌ی Class library دربرگیرنده‌ی TagHelper سفارشی است.
اکنون که این TagHelper در Viewهای برنامه قابل شناسایی است، روش افزودن آن، بر اساس همان سفارشی سازی‌هایی است که انجام دادیم:

مطالب
Virtual Scrolling در Angular 7
یکی از امکانات Angular 7، ویژگی Virtual Scrolling می‌باشد. در صورتیکه شما قصد داشته باشید یک لیست بزرگ از المنت‌ها را  بارگذاری کنید، این‌کار می‌تواند بر روی کارآیی برنامه‌ی شما تاثیر بگذارد . تگ زیر
<cdk-virtual-scroll-viewport></cdk-virtual-scroll-viewport>
می تواند برای بارگذاری تنها بخش‌های قابل مشاهده‌ی از یک لیست، بر روی صفحه نمایش استفاده شود و همچنین تنها آیتم‌هایی Render خواهند شد که می‌تواند آن‌ها را در صفحه نمایش جا دهد. اگر لیست بارگذاری شده را اسکرول کنیم، در این حالت المنت‌ها در DOM  به صورت پویا  load و unload می‌شوند. 
قبل از پیاده سازی ، لازم است Angular CLI  را به آخرین نسخه بروز رسانی کنیم. برای بروز رسانی Angular CLI  دستور زیر را اجرا می‌کنیم:
npm install -g @angular/cli
بعد از نصب با استفاده از ng version  نسخه‌ی Angular CLI  را بررسی می‌کنیم که باید بزرگتر از 7 باشد:

حالا نوبت به ایجاد یک پروژه‌ی جدید می‌باشد. با استفاده از دستور زیر یک پروژه جدید ایجاد می‌شود:
ng new angular7-virtualScrolling
بعد از تایید دستور بالا،  دو سؤال از شما پرسیده می‌شود؟
1- آیا قصد دارید Angular routing اضافه شود یا نه؟ ( در نسخه‌های قبلی با استفاده از routing--  این کار را انجام می‌دادیم)


2-انتخاب فرمت stylesheet که قصد استفاده‌ی از آن‌را دارید ( با کلید‌های جهتی بالا و پایین روی صحفه کلید می‌توانید یکی از گزینه‌ها را انتخاب کنید )


برای استفاده از Virtual Scrolling نیاز است پکیج زیر را نصب کنیم : 
npm install @angular/cdk@latest
بعد از نصب، دستور ng serve را اجرا می‌کنیم تا بررسی کنیم که برنامه به درستی اجرا می‌شود یا نه. سپس فایل app.module.ts را باز می‌کنیم و ScrollingModule را در بخش imports اضافه می‌کنیم. اکنون نیاز است تا یک آرایه را برای نمایش آیتم‌های لیست، تولید کنیم. قطعه کد زیر در فایل app.component.ts  قرار دارد که یک آرایه عددی را ایجاد می‌کند و تعدادی آیتم را به آن اضافه می‌کند:
  title = 'Angular 7 – Virtual Scrolling feature';
  scrollItems: number[] = [];
  constructor() {
    for (let index = 0; index < 10000; index++) {
      this.scrollItems.push(index);
    }
  }

در فایل app.component.html  قطعه کد زیر را قرار می‌دهیم:
    <div>
      <h4>
        {{this.title}}
      </h4>
      <cdk-virtual-scroll-viewport itemSize="100">
        <div *cdkVirtualFor="let n of scrollItems">Item {{n}}</div>
      </cdk-virtual-scroll-viewport>
    </div>

داخل تگ  cdk-virtual-scroll-viewport، یک div را ایجاد و سپس یک دایرکتیو را به نام cdkVirtualFor* به آن اضافه می‌کنیم. این دایرکتیو، ngFor* را درون cdk-virtual-scroll-viewport، جایگزین می‌کند که شما با استفاده از آن می‌توانید یک حلقه بر روی آرایه  scrollItems  جهت پیمایش ایجاد کنید.
تمام ! اکنون پروژه را اجرا کنید.
در اولین بار اجرا :    


بعد از اسکرول کردن لیست : 


همانطور که مشاهده می‌کنیم المنت‌های قبلی unload شدند و المنت‌های جدید load شدند
DEMO