<?xml version="1.0"?>
<rss version="2.0"><channel><title>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A; JavaScript</title><link>https://academy.hsoub.com/programming/javascript/page/15/?d=2</link><description>&#x627;&#x644;&#x628;&#x631;&#x645;&#x62C;&#x629;: &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A; JavaScript</description><language>ar</language><item><title>&#x645;&#x642;&#x62F;&#x645;&#x629; &#x625;&#x644;&#x649; WebGL - &#x625;&#x636;&#x627;&#x641;&#x629; &#x627;&#x644;&#x62A;&#x641;&#x627;&#x635;&#x64A;&#x644; &#x625;&#x644;&#x649; &#x633;&#x637;&#x62D; &#x645;&#x62C;&#x633;&#x651;&#x64E;&#x645;</title><link>https://academy.hsoub.com/programming/javascript/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-webgl-%D8%A5%D8%B6%D8%A7%D9%81%D8%A9-%D8%A7%D9%84%D8%AA%D9%81%D8%A7%D8%B5%D9%8A%D9%84-%D8%A5%D9%84%D9%89-%D8%B3%D8%B7%D8%AD-%D9%85%D8%AC%D8%B3%D9%91%D9%8E%D9%85-r489/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_05/main.png.7d3e2811c214891f157f0c372b582c0f.png" /></p>

<p>
	بعد تعلّم المعلومات الرئيسية عن الفضاء ثلاثي الأبعاد والإضاءة، تعجّلنا في نهاية <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-webgl-%D8%A7%D9%84%D8%AA%D9%86%D9%82%D9%84-%D9%81%D9%8A-%D8%A7%D9%84%D9%81%D8%B6%D8%A7%D8%A1-%D9%88%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D8%A7%D9%84%D8%A3%D8%B6%D9%88%D8%A7%D8%A1-r485/" rel="">الدرس السابق</a> لكي نحصل على صورة ثلاثية الأبعاد، إلا أنني سأعود قليلًا إلى الوراء وأشرح كائنات threeJS بالتفصيل قبل إعادة عرض الناتج مجددًا.
</p>

<p style="text-align: center;">
	<img alt="main.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23366" data-unique="nblw2ko3n" src="https://academy.hsoub.com/uploads/monthly_2017_05/main.png.7683cbde3e14e77ef53a693dcefe7bd9.png"></p>

<h2 id="التفاصيل">
	التفاصيل
</h2>

<p>
	أنشأنا في نهاية <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-webgl-%D8%A7%D9%84%D8%AA%D9%86%D9%82%D9%84-%D9%81%D9%8A-%D8%A7%D9%84%D9%81%D8%B6%D8%A7%D8%A1-%D9%88%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D8%A7%D9%84%D8%A3%D8%B6%D9%88%D8%A7%D8%A1-r485/" rel="">الدرس السابق</a> جسمًا كرويًا نمثّل به لكوكب المريخ:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3879_8" style="">
<span class="pln">let marsGeo </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> THREE</span><span class="pun">.</span><span class="typ">SphereGeometry</span><span class="pln"> </span><span class="pun">(</span><span class="lit">500</span><span class="pun">,</span><span class="pln"> </span><span class="lit">32</span><span class="pun">,</span><span class="pln"> </span><span class="lit">32</span><span class="pun">);</span></pre>

<p>
	تدعم مكتبة threeJS أشكالا هندسية مختلفة، من بينها الشكل الكروي الذي يُتحصَّل عليه بالدالة <code>SphereGeometry</code>. نمرّر للدالة في المعطى الأول قيمة نصف قطر الكرة (<code>500</code>)، عدد القطع الأفقية المكونة للكرة (<code>32</code>) وعدد القطع العموديّة (<code>32</code>). يُنشَأ كل جسمٍ افتراضيًا في نقطة المبدأ (<code>‎0, 0, 0</code>)، لذا لا حاجة إلى نقل الجسم.<br>
	ماذا يحدث لو قلّلنا عدد القطع إلى 4 في كل اتجاه من الكرة؟ الصورة الآتية تعرض أثر اختلاف عدد القطع (من اليسار إلى اليمين: <code>4</code> ثم <code>8</code> ثم <code>16</code> ثم <code>32</code> قطعة أفقيًا وشاقوليًا لكل جسم).<br>
	 
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="23364" href="https://academy.hsoub.com/uploads/monthly_2017_05/01-segment-comparison.jpg.58cf013709363c85f415cd0841979095.jpg" rel=""><img alt="01-segment-comparison.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="23364" data-unique="4w1vzn8it" src="https://academy.hsoub.com/uploads/monthly_2017_05/01-segment-comparison.thumb.jpg.f137833a00c3a9c20ef32bc87399de13.jpg"></a>
</p>

<p>
	يمكنك أن تلاحظ أنَّ حافة الجسم تصبح «خشنةً» كلما قلّ عدد القطع؛ ويبدو الجزء الأمامي من الجسم كرويًا بسبب الأضواء والمُظلِّلات (shaders، سأتحدث عن المُظلِّلات بعد قليل).
</p>

<p>
	<strong>كقاعدة عامة</strong>: كلما ازدادت عدد القطع الموجودة في أحد الأجسام كان «أنعم»؛ لكن زيادة عدد القطع له سلبياته، فالعدد الكبير من القطع يؤدي إلى زيادة وقت المعالجة اللازم لإظهار المشهد إضافةً إلى زيادة حجم الذاكرة اللازمة لعرضه.<br>
	عليك الموازنة بين الأمرين وذلك بتحديد دقة التفاصيل التي تحتاج لها في الجسم؛ فلو كانت الكرة بعيدةً جدًا أو صغيرةً جدًا، فلن تحتاج إلى قطعٍ كثيرة لكي تجعلها تبدو كرويةً، لكن إذا أردتَ إنشاء مشهدٍ يصوِّر الكوكب عن قرب، فعليك زيادة عدد القطع لتضمن أنَّ حواف الكرة ستبقى ناعمةً حتى لو اقتربنا كثيرًا من الكوكب.
</p>

<h2 id="تركيب-المواد">
	تركيب «المواد»
</h2>

<p>
	طبّقنا في آخر مثال مادة Phong ‏(Phong material) إلى الكرة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3879_8" style="">
<code class="hljs livecodeserver"><span class="pln">marsMaterial </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-built_in"><span class="kwd">new</span></span><span class="pln"> </span><span class="hljs-constant"><span class="pln">THREE</span></span><span class="pun">.</span><span class="typ">MeshPhongMaterial</span><span class="pun">(</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> color</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">0xff6600</span></span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">),</span></code></pre>

<p>
	Phong هي خوارزمية تظليل (Shader algorithm) كتبها أحد باحثي رسوميات الحاسوب الفيتناميين. الغرض من المُظلِّل هو تعريف كيفية تفاعل الضوء مع السطح ثلاثي الأبعاد: وكانت خوارزمية Phong سريعةً وكفاءتها عالية، ومثاليةً لعرض السطوح الناعمة.<br>
	يجب أن تُدمَج المادة مع كائن ثلاثي الأبعاد في threeJS لإنشاء mesh:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3879_8" style="">
<code class="hljs fix"><span class="hljs-attribute"><span class="pln">marsMesh </span></span><span class="pun">=</span><span class="hljs-string"><span class="pln"> </span><span class="kwd">new</span><span class="pln"> THREE</span><span class="pun">.</span><span class="typ">Mesh</span><span class="pun">(</span><span class="pln">marsGeo</span><span class="pun">,</span><span class="pln"> marsMaterial</span><span class="pun">);</span></span></code></pre>

<p>
	الناتج المعروض في المثال السابق بسيطٌ جدًا ولا يناسب غرضنا، فنحن نريد إنشاء كوكب، وليس كرةً برتقاليةً لامعة. ولإنشاء هذا الشعور، فعلينا تضمين المزيد من المواد ووضعها على الكرة، وذلك عبر Texture Loader:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3879_8" style="">
<code class="hljs cs"><span class="hljs-keyword"><span class="kwd">let</span></span><span class="pln"> loader </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">new</span></span><span class="pln"> THREE</span><span class="pun">.</span><span class="typ">TextureLoader</span><span class="pun">();</span></code></pre>

<p>
	هنالك الكثير من الجوانب التي تتعلق بالمواد المُشكِّلة للجسم، وأبرزها – في حالة كوكب المريخ – هو اللون، لكن سطح كوكب المريخ متنوع جدًا ولا يمكن تمثيله بلونٍ واحد. فالحل هو أخذ إحدى الخرائط التي أنشأتها المكوكات الفضائية واستعمالها على الكرة. استعملتُ في هذا المثال صورًا من <a href="http://www.celestiamotherlode.net/catalog/mars.php" rel="external nofollow">Celestia</a> ثم ضبطُها لتكوِّن خريطةً المواد لسطح الكوكب:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3879_8" style="">
<code class="hljs sql"><span class="pln">marsMaterial</span><span class="pun">.</span><span class="pln">map </span><span class="pun">=</span><span class="pln"> loader</span><span class="pun">.</span><span class="hljs-operator"><span class="hljs-keyword"><span class="pln">load</span></span><span class="pun">(</span><span class="pln">imgLoc</span><span class="pun">+</span><span class="hljs-string"><span class="str">"mars-map.jpg"</span></span><span class="pun">);</span></span></code></pre>

<p>
	ربما تتذكر من أوّل درس في هذه السلسلة أننا عرّفنا المتغير <code>imgLoc</code> الذي يحتوي على مسار تخزين الصور.
</p>

<h2 id="قياس-الخريطة-المستعملة-مع-webgl">
	قياس الخريطة المستعملة مع WebGL
</h2>

<p>
	على النقيض من عدد القطع التي تُشكِّل الجسم، من المستحسن استخدام خرائط ذات دقة عالية، لأنها تعطي شعورًا بدقة تفاصيل الجسم؛ لكن ذلك يؤدي إلى نفس المشاكل: استخدام ذاكرة أكثر، وتقليل الأداء.<br>
	أجرتَ WebGL موازنة بين ما سبق عبر وضع شرطين للخرائط المستعملة:
</p>

<ol>
<li>
		يجب أن يكون عرض وارتفاع الخريطة من قوى العدد 2: أي 1 أو 2 أو 4 أو 8 أو 16 أو 32 أو 64 أو 128 أو 256 أو 512 أو 1024 أو 2048 أو 4096 أو 8192 بكسل طولًا أو عرضًا (يمكن أن تختلف الأرقام. فمن الممكن أن تكون الخريطة بعرض 1024 وبارتفاع 512).
	</li>
	<li>
		هنالك حدٌّ أقصى لما تستطيع متصفحات الهاتف استعماله لخرائط الأجسام، وهذا الحد يرتفع مع مرور الوقت (نظام iOS 10 يدعم خريطةً بأبعاد 4096×4096، ويمكنك تجربة مختلف الأجهزة والأنظمة في <a href="http://webglreport.com/" rel="external nofollow">webglreport.com</a>).
	</li>
</ol>
<p>
	سأعيد تحجيم الخريطة التي سأستعملها إلى 4096‎×2048 بكسل:<br>
	 
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="23365" href="https://academy.hsoub.com/uploads/monthly_2017_05/02-mars-map.jpg.44d7cbd3bcc541a054a976260f65a804.jpg" rel=""><img alt="02-mars-map.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="23365" data-unique="im34a88ja" src="https://academy.hsoub.com/uploads/monthly_2017_05/02-mars-map.thumb.jpg.a2e56d539bb80bc7457714e70f0645ac.jpg"></a>
</p>

<p>
	‎من المهم أن تكون الخريطة سلسة الحواف (seamless): أي عندما توضع على كرة، فلن تكون حدودها واضحةً.
</p>

<h2 id="العرض">
	العرض
</h2>

<p>
	لإنتاج أيّ مشهد فعلينا «عرضه» (render)، وذلك باستخدام شفرة ذات خمسة أسطر، على النحو التالي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3879_8" style="">
<code class="hljs mel"><span class="kwd">let</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">renderer</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> THREE</span><span class="pun">.</span><span class="typ">WebGLRenderer</span><span class="pun">({</span><span class="pln">antialiasing </span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">});</span><span class="pln">
marsloc</span><span class="pun">.</span><span class="pln">appendChild</span><span class="pun">(</span><span class="hljs-keyword"><span class="pln">renderer</span></span><span class="pun">.</span><span class="pln">domElement</span><span class="pun">);</span><span class="pln">

</span><span class="kwd">function</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">render</span></span><span class="pun">(){</span><span class="pln">
    </span><span class="hljs-keyword"><span class="pln">renderer</span></span><span class="pun">.</span><span class="pln">setSize</span><span class="pun">(</span><span class="hljs-keyword"><span class="pln">window</span></span><span class="pun">.</span><span class="pln">innerWidth</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">window</span></span><span class="pun">.</span><span class="pln">innerHeight</span><span class="pun">);</span><span class="pln">
    </span><span class="hljs-keyword"><span class="pln">renderer</span></span><span class="pun">.</span><span class="hljs-keyword"><span class="pln">clear</span></span><span class="pun">();</span><span class="pln">
    </span><span class="hljs-keyword"><span class="pln">renderer</span></span><span class="pun">.</span><span class="hljs-keyword"><span class="pln">render</span></span><span class="pun">(</span><span class="pln">scene</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">camera</span></span><span class="pun">);</span><span class="pln"> 
</span><span class="pun">}</span></code></pre>

<p>
	استعملنا الخيار <code>antialiasing</code> لتنعيم شكل كوكب المريخ عند تعريف المتغير <code>renderer</code> (الذي يملك خياراتٍ كثيرة أخرى).<br>
	المتغير <code>marsLoc</code> هو العنصر الذي سيحتوي على مشهد WebGL والذي أنشأناه في <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-webgl-%D8%AA%D8%B9%D8%B1%D9%8A%D9%81-r481/" rel="">الجزء الأول</a>، حيث أضفنا <code>renderer</code> إليه.<br>
	أما داخل الدالة <code>render</code> فكانت أبعاد المشهد مساويةً لأبعاد نافذة المتصفح؛ ثم مسحنا كل ما كان موجودًا في لوح الرسم، ثم عرضنا المشهد باستخدام الكاميرا التي عرَّفناها سابقًا.<br>
	ستلاحظ الآن أنَّ النتيجة تبدو مسطحةً ولامعةً، وثابتةً في الفضاء، وغير متجاوبة؛ وسنتخذ التدابير اللازمة في الدرس القادم من هذه السلسلة لحلّ تلك المشاكل.
</p>

<p>
	ترجمة –وبتصرّف– للمقال <a href="http://thenewcode.com/1184/A-WebGL-Tour-of-the-Solar-System-Mars-Part-Three" rel="external nofollow">A WebGL Tour of the Solar System: Mars, Part Three</a>لصاحبهDudley Storey
</p>
]]></description><guid isPermaLink="false">489</guid><pubDate>Wed, 24 May 2017 08:38:42 +0000</pubDate></item><item><title>&#x645;&#x642;&#x62F;&#x645;&#x629; &#x625;&#x644;&#x649; WebGL - &#x627;&#x644;&#x62A;&#x646;&#x642;&#x644; &#x641;&#x64A; &#x627;&#x644;&#x641;&#x636;&#x627;&#x621; &#x648;&#x62A;&#x634;&#x63A;&#x64A;&#x644; &#x627;&#x644;&#x623;&#x636;&#x648;&#x627;&#x621;</title><link>https://academy.hsoub.com/programming/javascript/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-webgl-%D8%A7%D9%84%D8%AA%D9%86%D9%82%D9%84-%D9%81%D9%8A-%D8%A7%D9%84%D9%81%D8%B6%D8%A7%D8%A1-%D9%88%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D8%A7%D9%84%D8%A3%D8%B6%D9%88%D8%A7%D8%A1-r485/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_05/main.png.e3a28fe9abd980b647fb7f0cea04b596.png" /></p>

<p>
	شرحنا في <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-webgl-%D8%AA%D8%B9%D8%B1%D9%8A%D9%81-r481/" rel="">أوّل جزء</a> من هذه <a href="https://academy.hsoub.com/tags/webgl/" rel="">السلسلة</a> أساسيات استخدام إطار عمل threeJS، بما في ذلك ضبط إعدادات الكاميرا ودمج مشهد WebGL مع محتويات صفحة الوِب. أما في هذا الدرس فسنُموضع الكاميرا في الفضاء ثلاثي الأبعاد ونجعلها تُشير إلى كائن ونُضيف إضاءةً إلى المشهد. ولكن قبل فعل أيّ مما سبق، علينا أن نفهم طبيعة الفضاء ثلاثي الأبعاد.
</p>

<p style="text-align: center;">
	<img alt="main.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23280" data-unique="xegxup4q6" src="https://academy.hsoub.com/uploads/monthly_2017_05/main.png.385f9947de3910bfa2ab050409a3179e.png"></p>

<p>
	<u><strong>ملاحظة:</strong></u> هذا الدرس يكمل من حيث انتهى <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-webgl-%D8%AA%D8%B9%D8%B1%D9%8A%D9%81-r481/" rel="">الدرس السابق</a>، لذا عليك أن تفهمه وتحصل على شِفرته قبل الاستمرار بقراءة هذا الدرس.
</p>

<h2 id="التنقل-في-الفضاء-ثلاثي-الأبعاد">
	التنقل في الفضاء ثلاثي الأبعاد
</h2>

<p>
	أتوقع أنَّك تعرف محاور الإحداثيات من دراستك الثانوية: يُرسَم المحور <code>x</code> أفقيًا، والمحور <code>y</code> شاقوليًا (عموديّا). وبضبط الوحدات التي تُمثلها تلك المحاور، فسنتمكن من تحديد مكان أيّ عنصرٍ في الجزء الموجب من الفضاء ثنائي الأبعاد. أما إذا أردنا تضمين الأماكن السالبة فعلينا تمديد المحاور إلى اليسار وإلى الأسفل:
</p>

<p style="text-align: center;">
	<img alt="01-2D-space.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23277" data-unique="4ff3buety" src="https://academy.hsoub.com/uploads/monthly_2017_05/01-2D-space.png.6afaa386fa0ce3947d9da8b13944a654.png"></p>

<p>
	نقطة تقاطع المحورين هي النقطة <code>‎</code>0, 0 وتسمى «المبدأ» (Origin).<br>
	أما لتحديد المواقع في فضاء ثلاثي الأبعاد، فعلينا إضافة محور ثالث عمودي على المحورين السابقين ويتجه بعيدًا عن المشاهد. نستطيع تخيّل المحور <code>z</code> أيضًا بإمالة المنظور قليلًا كما في الرسم التوضيحي الآتي:
</p>

<p style="text-align: center;">
	<img alt="02-3D-space.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23278" data-unique="92mygndst" src="https://academy.hsoub.com/uploads/monthly_2017_05/02-3D-space.png.4ed9fb87ea684e7d912872ac30d06a83.png"></p>

<p>
	لاحظ أنَّ الجزء السالب من المحور <code>z</code> يتجه مبتعدًا عنّا، أما الجزء الموجب فهو أقرب.
</p>

<p>
	يمكن الآن تحديد مكان أيّة نقطة في الفضاء بتقاطع ثلاثة قيم <code>x</code> و<code>y</code> و<code>z</code>.
</p>

<p>
	<strong>ملاحظة:</strong> لاحظ عدم أهمية ما الذي تمثِّله تلك الأرقام، فقد تكون بوحدة المليمتر أو القدم أو السنوات الضوئية! المهم هو كيف تتفاعل تلك الأرقام مع بعضها: فالقيمة <code>2x</code> هي ضعف المسافة <code>x</code>.
</p>

<p>
	تتواجد الكاميرات التي أنشأناها في الدرس السابق في مبدأ الإحداثيات افتراضيًا، لكننا نريد وضعها بعيدًا عن المنتصف:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6364_11" style="">
<span class="pln">camera</span><span class="pun">.</span><span class="pln">position</span><span class="pun">.</span><span class="pln">set</span><span class="pun">(</span><span class="lit">1380</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">);</span></pre>

<p>
	المتغير <code>scene</code> يحتوي على الكائنات التي سنُنشِئها، والذي يُمكن تهيئته بالسطر الآتي:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6364_11" style="">
<code class="hljs fix"><span class="hljs-attribute"><span class="pln">scene </span></span><span class="pun">=</span><span class="hljs-string"><span class="pln"> </span><span class="kwd">new</span><span class="pln"> THREE</span><span class="pun">.</span><span class="typ">Scene</span><span class="pun">();</span></span></code></pre>

<p>
	يوضع المشهد تلقائيًا في مبدأ الإحداثيات (<code>‎0, 0, 0</code>) وسنضع فيه أيضًا العنصر الرئيسي الذي سنُنشِئه (كوكب المريخ). لذا نريد أن نوجِّه الكاميرا إلى تلك النقطة:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6364_11" style="">
<code class="hljs avrasm"><span class="pln">camera</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">lookAt</span></span><span class="pun">(</span><span class="pln">scene</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">position</span></span><span class="pun">)</span><span class="hljs-comment"><span class="pun">;</span></span></code></pre>

<p>
	<strong>ملاحظة:</strong> يمكن وضع الكاميرا – في هذا المثال– على المحور <code>z</code> أيضًا لكن يجب أن تبعد بنفس القيمة (1380)، ويمكن أيضًا وضعها في الجزء السالب من المحور <code>x</code> أو<code>z</code>؛ وذلك لأنَّ الكاميرا ستكون موجهةً نحو المبدأ دومًا.
</p>

<h2 id="لنشغل-الأضواء">
	لنشغِّل الأضواء
</h2>

<p>
	المشهد الذي أنشأناه هو فضاءٌ مظلمٌ لا متناهٍ، مما يعني أنَّ أي كائن سيوضع فيه سيكون غيرَ مرئي، لعدم وجود مصدر للضوء. لنضف واحدًا:
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6364_11" style="">
<code class="hljs rsl"><span class="hljs-shader"><span class="hljs-keyword"><span class="pln">light</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> THREE</span><span class="pun">.</span><span class="typ">PointLight</span><span class="pun">(</span></span><span class="hljs-number"><span class="lit">0xFFFFFF</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">2</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">5000</span></span><span class="pun">);</span><span class="pln">
</span><span class="hljs-shader"><span class="hljs-keyword"><span class="pln">light</span></span><span class="pun">.</span><span class="pln">position</span><span class="pun">.</span><span class="kwd">set</span><span class="pun">(</span></span><span class="hljs-number"><span class="lit">2000</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">2000</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">1500</span></span><span class="pun">);</span><span class="pln">
scene</span><span class="pun">.</span><span class="pln">add</span><span class="pun">(</span><span class="hljs-shader"><span class="hljs-keyword"><span class="pln">light</span></span><span class="pun">);</span></span></code></pre>

<p>
	<strong>ملاحظة:</strong> لاحظ أنَّك لن ترى شيئًا في هذه المرحلة، ليس لأنَّ مصدر الضوء يكون مخفيًّا افتراضيًا، وإنما لأننا لم نعرض المشهد بعد.
</p>

<p>
	تتوافر ستة أنواع من الأضواء في إطار عمل threeJS:
</p>

<ul>
<li>
		ضوء نقطي (<code>PointLight</code>): وهو الضوء الذي يكون له موضعٌ معيّن، ويُشعّ الضوء في كل الاتجاهات بقدر متساوٍ، مما يجعل هذا النوع من الإضاءة مثاليًا لمحاكاة الضوء الآتي من النجوم أو المصابيح.
	</li>
	<li>
		ضوء ذو اتجاه (<code>DirectionalLight</code>): وهو الضوء الذي له اتجاهٌ معيّن، لكنه ليس حزمةً ضوئيةً (Beam، على النقيض من «بقعة الضوء» Spotlight أدناه)، وهو مفيدٌ لمحاكاة طريقة رؤية أشعة الشمس من سطح الأرض.
	</li>
	<li>
		بقعة ضوء (<code>SpotLight</code>): الضوء الذي يُشير إلى اتجاهٍ معيّن يشبه حزمةً ضوئيةً واسعةً مَثَلُهُ كَمَثَلِ الأضواء المسرحية.
	</li>
	<li>
		الضوء الآتي من منطقة مضيئة مستطيلة (<code>RectAreaLight</code>) وهو مفيدٌ لمحاكاة الضوء المار عبر النافذة أو من لوحٍ من الفلورسنت.
	</li>
	<li>
		الإضاءة المحيطية (<code>AmbientLight</code>): هذا ضوءٌ عامٌ كالذي تراه آتيًا من جميع الاتجاهات. تخيل ليلةً غيرَ مقمرةٍ فيها ضوء محيطي. للإضاءة المحيطية القدرة على إضفاء لونٍ معيّن على المشهد: فكلما كان الضوء المحيطي فاتحًا كلما ظهر المشهد بلونٍ باهت.
	</li>
	<li>
		الإضاءة نصف الكروية (<code>HemisphereLight</code>): يدعى هذا النوع من الإضاءة في برامج التصميم ثلاثي الأبعاد بالمصطلح «Skylight». وهي تحاكي الضوء القادم من الأعلى (السماء) إلى الأسفل (أيّ نوع من الانعكاس أو الضوء من الأرض). يمكنك تخيّل هذا النوع من الإضاءة كما لو أنَّ الإضاءة المحيطية مقسومة إلى نصفين.
	</li>
</ul>
<p>
	سأشرح أنواع الإضاءة السابقة تفصيليًا في مقالاتٍ قادمة، لكن علينا أن نركِّز الآن على الضوء النقطي والذي يأخذ ثلاثة وسائط: اللون (عبر قيمة بالنظام الست عشري، يسبقها <code>‎0x</code>)، والشدة (Intensity)، والنقطة التي سيبدأ الضوء بالانتشار منها.
</p>

<blockquote class="ipsQuote" data-ipsquote="">
	<div class="ipsQuote_citation">
		Quote
	</div>

	<div class="ipsQuote_contents ipsClearfix">
		<p>
			في الحياة الواقعية، يتَّبِع الضوءُ قانونَ التربيعِ العكسي (Inverse-square law) الذي ينص على أنَّ شدة الضوء تتناسب عكسيًا مع مربع المسافة من المصدر. وهذا يحدث فوريًا ومباشرةً بعد خروج الفوتون (photon) من المصدر الضوئي. أما في النمذجة ثلاثية الأبعاد، فستجد أنَّ هذا القانون سيُسبِّب مشاكل: فمن السهل إنشاء مصدر ضوئي تظن أنَّه قويٌ كفايةً لتجد أنَّ شدته قد قلَّت بسرعة. ولهذا السبب يشيع ضبط مسافةٍ لبدء تناقص شدة الضوء في الرسومات ثلاثية الأبعاد منها: حيث يكون الضوء بكامل شدته من المصدر إلى تلك النقطة، ثم تبدأ شدته بالتناقص تدريجيًا بدءًا من تلك النقطة.
		</p>
	</div>
</blockquote>

<p>
	وكذلك الأمر فيما يتعلق بالظلال، فجميع الأضواء تلقي بظلالٍ في الواقع، أما في الرسومات ثلاثية الأبعاد فقد يُسبِّب ذلك مشاكل، لذا يكون إلقاء الظلال الناتجة من الضوء اختياريًا.<br>
	ربما تُفضِّل التجربة مع شدة الضوء لترى تأثيرها، حيث ستجد أنَّ الشدة العالية للضوء ستجعل الألوان قويةً جدًا، مثل استخدام ضوء فلاش قوي جدًا بالقرب من الجسم الذي تصوِّره بكاميرتك العادية.
</p>

<h2 id="نموذج-أولي-بسيط">
	نموذج أولي بسيط
</h2>

<p>
	يؤسفني أن نخوض في كل المعلومات السابقة دون أن تتاح لنا فرصةٌ لرؤية أيّة أشكال في صفحتنا، لذا أنشأتُ نسخةً مبسطةً من الناتج وعرضتها لك. الشيفرة الآتية تضم جميع التعليمات البرمجية التي كتبناها منذ بداية هذه <a href="https://academy.hsoub.com/tags/webgl/" rel="">السلسلة</a> وحتى هذه المرحلة (دون الشفرة المسؤولة عن تضمين إطار threeJS):
</p>

<pre class="ipsCode prettyprint lang-py prettyprinted" id="ips_uid_6364_11" style="">
<code class="hljs avrasm"><span class="kwd">let</span><span class="pln"> camera </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> THREE</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">PerspectiveCamera</span></span><span class="pun">(</span><span class="hljs-number"><span class="lit">45</span></span><span class="pun">,</span><span class="pln"> window</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">innerWidth</span></span><span class="pln"> </span><span class="pun">/</span><span class="pln"> window</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">innerHeight</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">0.1</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">10000</span></span><span class="pun">),</span><span class="pln">
light </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> THREE</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">PointLight</span></span><span class="pun">(</span><span class="hljs-number"><span class="lit">0xFFFFFF</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">2</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">5000</span></span><span class="pun">),</span><span class="pln">
scene </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> THREE</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Scene</span></span><span class="pun">()</span><span class="hljs-comment"><span class="pun">;</span></span><span class="pln">
light</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">position</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="kwd">set</span></span><span class="pun">(</span><span class="hljs-number"><span class="lit">2000</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">2000</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">1500</span></span><span class="pun">)</span><span class="hljs-comment"><span class="pun">;</span></span><span class="pln">
camera</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">position</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="kwd">set</span></span><span class="pun">(</span><span class="hljs-number"><span class="lit">1500</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">)</span><span class="hljs-comment"><span class="pun">;</span></span><span class="pln">
camera</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">lookAt</span></span><span class="pun">(</span><span class="pln">scene</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">position</span></span><span class="pun">)</span><span class="hljs-comment"><span class="pun">;</span></span><span class="pln">
scene</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">add</span></span><span class="pun">(</span><span class="pln">light</span><span class="pun">)</span><span class="hljs-comment"><span class="pun">;</span></span><span class="pln">

</span><span class="kwd">let</span><span class="pln"> marsGeo </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> THREE</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">SphereGeometry</span></span><span class="pln"> </span><span class="pun">(</span><span class="hljs-number"><span class="lit">500</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">32</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">32</span></span><span class="pun">),</span><span class="pln">
marsMaterial </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> THREE</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">MeshPhongMaterial</span></span><span class="pun">(</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> color</span><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">0xff6600</span></span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="pun">),</span><span class="pln">
marsMesh </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> THREE</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">Mesh</span></span><span class="pun">(</span><span class="pln">marsGeo</span><span class="pun">,</span><span class="pln"> marsMaterial</span><span class="pun">)</span><span class="hljs-comment"><span class="pun">;</span></span><span class="pln">
scene</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">add</span></span><span class="pun">(</span><span class="pln">marsMesh</span><span class="pun">)</span><span class="hljs-comment"><span class="pun">;</span></span><span class="pln">
</span><span class="kwd">let</span><span class="pln"> renderer </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> THREE</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">WebGLRenderer</span></span><span class="pun">()</span><span class="hljs-comment"><span class="pun">;</span></span><span class="pln">
renderer</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">setSize</span></span><span class="pun">(</span><span class="pln">window</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">innerWidth</span></span><span class="pun">,</span><span class="pln"> window</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">innerHeight</span></span><span class="pun">)</span><span class="pln">       
marsloc</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">appendChild</span></span><span class="pun">(</span><span class="pln">renderer</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">domElement</span></span><span class="pun">)</span><span class="hljs-comment"><span class="pun">;</span></span><span class="pln">
renderer</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">render</span></span><span class="pun">(</span><span class="pln">scene</span><span class="pun">,</span><span class="pln"> camera</span><span class="pun">)</span><span class="hljs-comment"><span class="pun">;</span></span></code></pre>

<p>
	بوضع الشيفرة السابقة في صفحة الويب التي أنشأناها في الدرس السابق، فسترى <a href="https://codepen.io/dudleystorey/pen/bgKRov" rel="external nofollow">النتيجة الآتية</a>؛ لكن ما يزال علينا إضافة الكثير من الأمور إليها، وشرحها بالتفصيل، وهذا ما سنفعله في الدرس القادم.
</p>

<p>
	ترجمة –وبتصرّف– للمقال <a href="http://thenewcode.com/1179/A-WebGL-Tour-of-the-Solar-System-Mars-Part-Two" rel="external nofollow">A WebGL Tour of the Solar System: Mars, Part Two</a> لصاحبه Dudley Storey.
</p>
]]></description><guid isPermaLink="false">485</guid><pubDate>Wed, 17 May 2017 15:22:10 +0000</pubDate></item><item><title>&#x645;&#x642;&#x62F;&#x645;&#x629; &#x625;&#x644;&#x649; WebGL - &#x62A;&#x639;&#x631;&#x64A;&#x641;</title><link>https://academy.hsoub.com/programming/javascript/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-webgl-%D8%AA%D8%B9%D8%B1%D9%8A%D9%81-r481/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_05/main2.png.a136fecfb85f74938e5987735c694d87.png" /></p>

<p>
	كانت هنالك الكثير من المحاولات الباكرة لابتكار تقنية لإنشاء رسوميات ثلاثية الأبعاد 3D تفاعلية في صفحات الوِب، بما فيها <a href="https://en.wikipedia.org/wiki/VRML" rel="external nofollow">VRML</a> وFlash، لكن لم يظهر معيارٌ متكاملٌ حتى عام 2013 ألا وهو WebGL المبني على OpenGL ES 2.0، لذا أصبح بإمكاننا تضمين رسوميات 3D تفاعلية في صفحات الوِب دون الحاجة إلى أيّة إضافات أو ملحقات للمتصفح.
</p>

<p style="text-align: center;">
	<img class="ipsImage ipsImage_thumbnailed" data-fileid="23279" data-unique="hb5sj4x6v" src="https://academy.hsoub.com/uploads/monthly_2017_05/main2.png.9e4414ec2f61acf7b04173f2c4c40cbc.png" alt="main2.png"></p>

<h2 id="ما-هي-تقنية-webgl">
	ما هي تقنية WebGL؟
</h2>

<p>
	تسمح تقنية WebGL بكتابة رسوميات 3D في صفحات الويب باستخدام <a href="https://academy.hsoub.com/programming/javascript/" rel="">JavaScript</a> عبر العنصر <code>&lt;canvas&gt;</code>، لكن تقنية WebGL لا تُنشِئ «عناصر» على الصفحة، إذ تتعامل مباشرةً مع البكسلات؛ وبالتالي نقول عن تقنية WebGL أنّها تقنيةٌ منخفضة المستوى: حيث توفِّر تحكمًا دقيقًا بالفضاء ثلاثي الأبعاد.<br>
	وعلى النقيض من أغلبية تطبيقات 3D، لا تتضمن WebGL «مشاهد» (Scenes) أو «كائنات» (Objects) أو «نماذج» (Models). وهذا ما يجعلها تقنيةً قويةً جدًا، لكن في الوقت نفسه تُصعِّب عملية التعلم بالنسبة للمطورين، ولا يمكن إخراج النتائج بواسطتها بسرعة.
</p>

<p>
	صحيحٌ أنَّ من الممكن تقنيّا كتابة شِفرات WebGL عبر JavaScript مباشرة، لكن أغلبية المطورين يستعملون إطار عمل Framework، وأشهر إطار عمل لتقنية WebGL هو <a href="https://threejs.org/" rel="external nofollow">threeJS</a>، لكن هنالك <a href="https://en.wikipedia.org/wiki/List_of_WebGL_frameworks" rel="external nofollow">خياراتٌ أخرى</a> عداه.
</p>

<h2 id="الحاجة-إلى-إطار-عمل">
	الحاجة إلى إطار عمل
</h2>

<p>
	أنصح دومًا بالابتعاد عن أطر العمل: فأنا أعتقد أنَّ المطورين سيتعلمون أمورًا تفيدهم في المستقبل إذا تمكنوا من فهم الأساسيات التي تُبنَى عليها تقنيةٌ ما، بدلًا من سَلك «طرق مختصرة». لكنّ الرسم ثلاثي الأبعاد موضوعٌ معقدٌ جدًا، ومحاولة بناء خبرة عملية باستخدام WebGL إضافةً إلى تعلم تقنيات الوِب الأخرى أمرٌ صعبٌ للكثيرين، وتعلّم أساسيات WebGL يعني إضاعة الكثير من الوقت في التعلم دون القدرة على إنشاء أيّة رسومات ولو كانت بسيطةً.
</p>

<p>
	لهذا السبب، سنستعمل في شرحنا لهذه التقنية إطار threeJS، ولا أفترض عند كتابتي لهذه <a href="https://academy.hsoub.com/tags/webgl/" rel="">السلسلة</a> أنَّ القارئ على دراية بمبادئ الرسم ثلاثي الأبعاد، لكن يجب أن يكون ذا درايةٍ جيدة بتقنيات <a href="https://academy.hsoub.com/programming/html5/" rel="">HTML</a> و<a href="https://academy.hsoub.com/programming/css/" rel="">CSS</a> وJavaScript.
</p>

<p>
	سنستخدم في هذه السلسلة آخر إصدار متوافر من إطار threeJS.
</p>

<h2 id="ما-الذي-يجعل-هذه-السلسلة-مختلفة-عن-غيرها">
	ما الذي يجعل هذه السلسلة مختلفةً عن غيرها
</h2>

<p>
	أغلبية الدروس التعليمية التي تتحدث عن threeJS والمتوافرة على الوِب هي دروسٌ ليست بالمستوى المطلوب، حيث لا تعمل الأمثلة الحية لعدم تحديث الشفرة منذ فترةٍ طويلةٍ (تأتي التحديثات والتحسينات على إطار عمل threeJS بين الحين والآخر)، وهنالك خطواتٌ كاملةٌ غيرُ مشروحةٍ. لذا سأبذل جهدي لتفادي ذلك في هذه السلسلة، حيث سأضع المعلومات بتسلسلٍ منطقيٍ شارحا باستفاضة، مستعملًا أمثلةً عمليةً مسليةً ألا وهي نمذجة الكواكب الموجودة في نظامنا الشمسي كرسومات 3D.
</p>

<h2 id="بناء-كوكب-المريخ-باستخدام-webgl">
	بناء كوكب المريخ باستخدام WebGL
</h2>

<p>
	بعد أن تعرفنا على WebGL وتحدثنا أننا سنستعمل إطار العمل threeJS للاستفادة من إمكانية WebGL لإنشاء رسوميات 3D في صفحات الويب التي نُنشِئها، فسنكمل تعلمنا في بقية هذا الدرس (وفي الدروس القادمة) بإنشاء نموذج لكوكب المريخ؛ وسنستهل الأمر بتعلم كيفية وضع كاميرا ثلاثية الأبعاد، والتحكم بتفاعل محتوى WebGL مع بقية صفحة HTML الموجود داخلها.
</p>

<p style="text-align: center;">
	<img alt="01-mars-pres.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="23185" data-unique="7yd7qf00m" src="https://academy.hsoub.com/uploads/monthly_2017_05/01-mars-pres.jpg.7d86c31456de33f8392faaf544bda1d4.jpg"></p>

<p>
	<br><strong>ملاحظة:</strong> سنشرح كل خطوة بالتفصيل أثناء بنائنا للنموذج، لذا لن يكون لدينا مشهدٌ جاهزٌ في نهاية هذا الدرس، وإنما سنفعل ذلك في المقالات اللاحقة المبنية على هذه المقالة (والمستقلة عنها)، أما لو كنتَ متحمسًا لرؤية الناتج النهائي، فاطلع على <a href="https://codepen.io/dudleystorey/pen/VmJKXe" rel="external nofollow">هذه التجربة الحية</a>.
</p>

<h3 id="تهيئة-الصفحة">
	تهيئة الصفحة
</h3>

<p>
	على الرغم من إمكانية استخدام عناصر WebGL بمفردها في الصفحة، إلا أنها تُصنَّف كتقنية وِب معيارية، مما يعني أنَّها تندمج اندماجًا كاملًا مع محتوى HTML، ولعدم امتلاك العنصر <code>&lt;canvas&gt;</code> ميزات تتعلق بقابلية الوصول وتحسين <a href="https://academy.hsoub.com/marketing/search-engine-optimisation/" rel="">أرشفة محركات البحث</a> للصفحة، فمن المنطقي أن نُنشِئ محتوى WebGL ضمن صفحة وِب فيها معلوماتٌ تشرح محتواه، وذلك بوضع النص ضمن شيفرات HTML، ثم إضافة محتوى WebGL عند الحاجة. وسنؤسِّس لصفحتنا –التي تتحدث عن المريخ– باستعمال الشيفرة الآتية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9236_7" style="">
<span class="pun">&lt;</span><span class="pln">div id</span><span class="pun">=</span><span class="str">"marsloc"</span><span class="pun">&gt;&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">article id</span><span class="pun">=</span><span class="str">"marsinfo"</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Mars</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">p</span><span class="pun">&gt;</span><span class="typ">Home</span><span class="pln"> to both the </span><span class="typ">Solar</span><span class="pln"> </span><span class="typ">System</span><span class="pun">’</span><span class="pln">s highest mountain</span><span class="pun">…</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">article</span><span class="pun">&gt;</span></pre>

<p>
	سيوضع محتوى WebGL ضمن العنصر <code>marsloc</code>، وسيوضَع النص الموجود في عنصر <code>&lt;div&gt;</code> فوق جميع محتويات الصفحة. هذه هي شِفرة <a href="https://academy.hsoub.com/programming/css/sass/" rel="">Sass</a> التي تتحكم بمظهر الصفحة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9236_7" style="">
<code class="hljs scss"><span class="hljs-tag"><span class="pln">body</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="hljs-attribute"><span class="pln">background</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> black</span><span class="pun">;</span></span><span class="pln">
  </span><span class="hljs-attribute"><span class="pln">margin</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">;</span></span><span class="pln">
  </span><span class="hljs-attribute"><span class="pln">min</span><span class="pun">-</span><span class="pln">height</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">100</span></span><span class="lit">vh</span><span class="pun">;</span></span><span class="pln">
  </span><span class="hljs-attribute"><span class="pln">color</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> </span><span class="hljs-hexcolor"><span class="com">#fff</span></span><span class="com">;</span></span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="hljs-id"><span class="com">#marsloc</span></span><span class="com"> {</span><span class="pln">
  </span><span class="hljs-attribute"><span class="pln">cursor</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> grab</span><span class="pun">;</span></span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="hljs-id"><span class="com">#marsinfo</span></span><span class="com"> { </span><span class="pln">
  </span><span class="hljs-attribute"><span class="pln">position</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> absolute</span><span class="pun">;</span></span><span class="pln">
  </span><span class="hljs-attribute"><span class="pln">top</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">;</span></span><span class="pln">
  </span><span class="hljs-attribute"><span class="pln">width</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">100</span></span><span class="pun">%;</span></span><span class="pln">
  </span><span class="hljs-attribute"><span class="pln">padding</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">2</span></span><span class="lit">rem</span><span class="pun">;</span></span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="hljs-id"><span class="com">#marsinfo</span></span><span class="com"> </span><span class="hljs-tag"><span class="com">h1</span></span><span class="com"> {</span><span class="pln">
  </span><span class="hljs-attribute"><span class="pln">font</span><span class="pun">-</span><span class="pln">size</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">8</span></span><span class="lit">vw</span><span class="pun">;</span></span><span class="pln">
  </span><span class="hljs-attribute"><span class="pln">margin</span><span class="pun">-</span><span class="pln">top</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">;</span></span><span class="pln">
  </span><span class="hljs-attribute"><span class="pln">font</span><span class="pun">-</span><span class="pln">weight</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">100</span></span><span class="pun">;</span></span><span class="pln">
  </span><span class="hljs-attribute"><span class="pln">line</span><span class="pun">-</span><span class="pln">height</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">1</span></span><span class="pun">;</span></span><span class="pln">
  </span><span class="hljs-attribute"><span class="pln">position</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> absolute</span><span class="pun">;</span></span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="hljs-id"><span class="com">#marsinfo</span></span><span class="com"> </span><span class="hljs-tag"><span class="com">div</span></span><span class="com"> {</span><span class="pln">
  </span><span class="hljs-attribute"><span class="pln">width</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">40</span></span><span class="pun">%;</span></span><span class="pln">
  </span><span class="hljs-attribute"><span class="pln">position</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> absolute</span><span class="pun">;</span></span><span class="pln">
  </span><span class="hljs-attribute"><span class="pln">background</span><span class="pun">-</span><span class="pln">color</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> rgba</span><span class="pun">(</span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">,</span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">,</span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">,</span><span class="hljs-number"><span class="lit">0.3</span></span><span class="pun">);</span></span><span class="pln">
  </span><span class="hljs-attribute"><span class="pln">right</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">;</span></span><span class="pln">
  </span><span class="hljs-attribute"><span class="pln">padding</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">1.3</span></span><span class="lit">rem</span><span class="pun">;</span></span><span class="pln">
  </span><span class="hljs-attribute"><span class="pln">line</span><span class="pun">-</span><span class="pln">height</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">1.6</span></span><span class="pun">;</span></span><span class="pln">
  </span><span class="hljs-attribute"><span class="pln">font</span><span class="pun">-</span><span class="pln">size</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">1.2</span></span><span class="lit">rem</span><span class="pun">;</span></span><span class="pln">
  </span><span class="hljs-attribute"><span class="pln">pointer</span><span class="pun">-</span><span class="pln">events</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> none</span><span class="pun">;</span></span><span class="pln">
  </span><span class="hljs-at_rule"><span class="lit">@</span><span class="hljs-keyword"><span class="lit">media</span></span><span class="hljs-preprocessor"><span class="pln"> all</span></span><span class="hljs-preprocessor"><span class="pln"> </span><span class="kwd">and</span></span><span class="pln"> </span><span class="pun">(</span><span class="pln">max</span><span class="pun">-</span><span class="pln">width</span><span class="pun">:</span><span class="hljs-preprocessor"><span class="pln"> </span><span class="lit">540px</span></span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span></span><span class="pln">
    </span><span class="hljs-attribute"><span class="pln">width</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">100</span></span><span class="pun">%;</span></span><span class="pln">
    </span><span class="hljs-attribute"><span class="pln">left</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">;</span></span><span class="pln">
    </span><span class="hljs-attribute"><span class="pln">top</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">40</span></span><span class="lit">vw</span><span class="pun">;</span></span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></code></pre>

<p>
	تغيير شكل مؤشر الفأرة في العنصر <code>‎#marsloc</code> سيُدلُّ على محتوى WebGL، أما العنصر <code>div</code> الموجود في <code>‎#marsloc</code> فله الخاصية <code>pointer-events: none</code> لذا لن يتأثر النص الموجود أعلى محتوى WebGL بالتعديلات التي نجريها على الكوكب.
</p>

<h3 id="إنشاء-الكوكب">
	إنشاء الكوكب
</h3>

<p>
	بعد كتابة شفرات HTML و CSS، فلنحمِّل آخر إصدار من threeJS من CDN في أسفل الصفحة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9236_7" style="">
<code class="hljs xml"><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">script</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">src</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"https://cdnjs.cloudflare.com/ajax/libs/three.js/r83/three.js"</span></span><span class="tag">&gt;</span></span><span class="javascript"><span class="pln">
</span></span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">script</span></span><span class="tag">&gt;</span></span></code></pre>

<p>
	<strong>ملاحظة:</strong> علينا أن نضمن وجود إطار عمل threeJS قبل كتابة أيّة شفرات تتعلق به.
</p>

<p>
	سيبدأ السكربت بضبط مجموعة من المتغيرات والثوابت التي سنستعملها في شيفرتنا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9236_7" style="">
<code class="hljs cs"><span class="hljs-keyword"><span class="kwd">var</span></span><span class="pln"> container</span><span class="pun">,</span><span class="pln"> controls</span><span class="pun">,</span><span class="pln"> camera</span><span class="pun">,</span><span class="pln"> renderer</span><span class="pun">,</span><span class="pln"> scene</span><span class="pun">,</span><span class="pln"> light</span><span class="pun">,</span><span class="pln"> marsMesh</span><span class="pun">,</span><span class="pln">
clock </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">new</span></span><span class="pln"> THREE</span><span class="pun">.</span><span class="typ">Clock</span><span class="pun">();</span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">const</span></span><span class="pln"> imgLoc </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">"https://s3-us-west-2.amazonaws.com/s.cdpn.io/4273/"</span></span><span class="pun">;</span></code></pre>

<p>
	سنستخدم المتغير <code>clock</code> للمساعدة في الحركة الافتراضية لكوكب المريخ، أما <code>imgLoc</code> فهو ثابتٌ يُشير إلى موقع جميع الصور التي سنستعملها وعرّفناه في البداية كي لا نُكرِّر المسار لاحقًا.
</p>

<h3 id="مجال-الرؤية">
	مجال الرؤية
</h3>

<p>
	أوّل عنصر سنُنشِئه هو الكاميرا، وهذا أمرٌ ضروريٌ لنتمكن من «رؤية» المشهد الذي سنُنشِئه. يوجد نوعان من الكاميرات في إطار threeJS:
</p>

<ul>
<li>
		المنظور (<code>perspectiveCamera</code>): الخطوط المتوازية الموجودة في المشهد ستتقارب من بعضها إذا امتدت لمسافة طويلة (تخيل نفسك واقفًا على سكةٍ حديديةٍ وتنظر إلى أبعد جزء ينتهي إليه بصرك)؛ وستبدو الأجسام البعيدة من الكاميرا صغيرةً. وهذه مشابه لآلية عمل بصرنا، وسيبدو المشهد من هذا النوع من الكاميرات واقعيًا.
	</li>
	<li>
		الإسقاط العمودي (<code>OrthographicCamera</code>): الخطوط المتوازية ستبقى متوازية بغض النظر عن مدى امتدادها؛ ولنفس السبب، لن تبدو الأجسام أصغر كلما ابتعدت عن الكاميرات. نستفيد من هذا النوع من الكاميرات عند رسم عناصر الواجهة الرسومية أو لبعض المناظير المعمارية.
	</li>
</ul>
<p>
	إذا كنّا سنستخدم كاميرا ذات منظور (<code>perspectiveCamera</code>) فعلينا أن نُعرِّف مجال الرؤية (يُشار إليه عادةً بالاختصار FOV، الذي يرمز إلى Field of view). يُحدِّد مجال الرؤية مدى اتساع «رؤية» الكاميرا. فمجال الرؤية الضيق (الذي يشبه الغِماء Blinker الذي يضعونه على أعين الخيول التي تجر العربات، كيلا تجزع الأحصنة مما حولها) يؤدي إلى «تركيز» الكاميرا ugn جزءٍ مُحدّد من المشهد، مما يؤدي إلى عدم إظهار بعض العناصر لأنها ستقع خارج مجال الرؤية. أما مجال الرؤية العريض فيؤدي إلى إظهار المزيد من الأجسام، لكنه يُسبِّب في جعلها تبدو أصغر وأبعد.<br>
	علينا أيضًا ضبط نسبة العرض إلى الارتفاع Aspect ratio: أي ما هو عرض المشهد نسبةً إلى ارتفاعه. من المرجّح أنَّك قد سمعتَ بنسبة العرض إلى الارتفاع في الأفلام، فالأفلام ذات المشاهد «العريضة» تجنح لأن تكون أفلام «ملحمية»، أما الأفلام التي نسبة العرض إلى الارتفاع قليلة (تكاد أن تصبح مربعةً) فستشعر أنها أفلامٌ قديمة.<br>
	نريد غالب الأوقات أن تتشابه نسبة العرض إلى الارتفاع في المشهد مع نسبة العرض إلى الارتفاع التابعة لنافذة المتصفح للزائر.
</p>

<p>
	آخر قيمتين علينا ضبطهما للكاميرا هما قيمتا لوحي القص Clipping plane البعيد والقريب. مبدئيا، تستطيع الكاميرات ثلاثية الأبعاد أن «ترى» إلى مسافة لا متناهية (على النقيض من المشاهد الواقعية)، أي لا توجد محدوديات في العدسات المستعملة في الكاميرات ثلاثية الأبعاد ولا توجد جزئيات في طبقات الجو تعرقل رؤيتها. يُشار إلى ذلك في الألعاب بالمصطلح «مسافة الرؤية» (أو مسافة الرسم، Draw distance)، وهذا هو أحد أسباب استخدام الضباب في الألعاب ثلاثية الأبعاد القديمة: فكلما قلَّ عدد العناصر التي يجب تحميلها كانت اللعبة أسرع.
</p>

<p>
	وفي حالتنا، نريد أن يكون لوح القص القريب Near clipping plane قريبًا جدًا إلى «عدسة» الكاميرا، ولوح القص البعيد Far clipping plane على مسافةٍ معقولة، وبالتالي ستحتوى العناصر التي نريد عرضها بين هذين اللوحين.
</p>

<p style="text-align: center;">
	<br><a class="ipsAttachLink ipsAttachLink_image" data-fileid="23186" href="https://academy.hsoub.com/uploads/monthly_2017_05/02-camera.png.c65b8fa3b97294b122be223e6aa48ff3.png" rel=""><img alt="02-camera.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23186" data-unique="qc8zvda22" src="https://academy.hsoub.com/uploads/monthly_2017_05/02-camera.thumb.png.dc5aa3df93bc9241a57f018178ecbe11.png"></a>
</p>

<p>
	الشفرة التي سنستعملها لفعل ذلك هي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_9236_7" style="">
<code class="hljs avrasm"><span class="pln">camera </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> THREE</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="typ">PerspectiveCamera</span></span><span class="pun">(</span><span class="hljs-number"><span class="lit">45</span></span><span class="pun">,</span><span class="pln"> 
window</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">innerWidth</span></span><span class="pln"> </span><span class="pun">/</span><span class="pln"> window</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">innerHeight</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">0.1</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">10000</span></span><span class="pun">)</span><span class="hljs-comment"><span class="pun">;</span></span></code></pre>

<p>
	أصبحتَ لدينا الآن كاميرا ثلاثية الأبعاد، لكنها موجودة في فضاء أسود لا متناهي، ولا تُشير إلى أيّ شيءٍ بعد؛ لكننا سنشرح في <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D9%82%D8%AF%D9%85%D8%A9-%D8%A5%D9%84%D9%89-webgl-%D8%A7%D9%84%D8%AA%D9%86%D9%82%D9%84-%D9%81%D9%8A-%D8%A7%D9%84%D9%81%D8%B6%D8%A7%D8%A1-%D9%88%D8%AA%D8%B4%D8%BA%D9%8A%D9%84-%D8%A7%D9%84%D8%A3%D8%B6%D9%88%D8%A7%D8%A1-r485/" rel="">الدرس القادم</a> طبيعة الفضاء ثلاثي الأبعاد، وكيفية إضاءته، وطريقة إضافة العناصر إلى المشهد.
</p>

<p>
	ترجمة –وبتصرّف– للمقال <a href="http://thenewcode.com/1171/Introduction-to-WebGL" rel="external nofollow">Introduction to WebGL</a> وللمقال <a href="http://thenewcode.com/1176/A-WebGL-Tour-of-the-Solar-System-Mars-Part-One" rel="external nofollow">A WebGL Tour of the Solar System: Mars, Part One</a> لصاحبهما Dudley Storey.
</p>
]]></description><guid isPermaLink="false">481</guid><pubDate>Thu, 11 May 2017 21:08:00 +0000</pubDate></item><item><title>&#x645;&#x62A;&#x649; &#x646;&#x633;&#x62A;&#x639;&#x645;&#x644; &#x625;&#x637;&#x627;&#x631; &#x639;&#x645;&#x644; &#x644;&#x644;&#x62A;&#x637;&#x648;&#x64A;&#x631; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; JavaScript</title><link>https://academy.hsoub.com/programming/javascript/%D9%85%D8%AA%D9%89-%D9%86%D8%B3%D8%AA%D8%B9%D9%85%D9%84-%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-%D9%84%D9%84%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-javascript-r477/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_05/Untitled-1.png.17ec6bbe2debc7bc74836a406774a08b.png" /></p>
<p>
	لا يجب أن تبدأ دائمًا بالتطوير باستعمال إطار عمل JavaScript، لكن هنالك حالات يكون فيها استعمال إطار العمل أمرًا منطقيًا.
</p>

<p>
	منذ فترةٍ كتبتُ مقالةً بعنوان «<a href="https://academy.hsoub.com/programming/javascript/%D9%84%D9%85%D8%A7%D8%B0%D8%A7-%D9%8A%D8%AF%D9%81%D8%B9%D9%86%D8%A7-%D8%A7%D9%84%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A8%D9%84%D8%BA%D8%A9-javascript-%D8%A5%D9%84%D9%89-%D8%AD%D8%A7%D9%81%D8%A9-%D8%A7%D9%84%D8%AC%D9%86%D9%88%D9%86-r446/" rel="">لماذا يدفعنا التطوير بلغة JavaScript إلى حافة الجنون!</a>» والتي زارها الكثيرون، وظهر التساؤلان الآتيان ردًا عليها:
</p>

<p>
	- متى يجب أن نستخدم إطار عمل؟
</p>

<p>
	- إذا لم نستعمل إطار عمل، فكيف نبدأ؟
</p>

<p style="text-align: center;">
	<img alt="Untitled-1.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23084" data-unique="sg8cdhjkd" src="https://academy.hsoub.com/uploads/monthly_2017_05/Untitled-1.png.7f6e9f39520f3e0369f10412f45c79f4.png">
</p>

<p>
	سأحاول في هذه المقالة الإجابة على التساؤل الأول، أما سؤال كيفية البدء إذا لم نستعمل إطار عمل فهو سؤالٌ أكبر، ويحتاج تفصيلًا أكثر.
</p>

<p>
	بدأتُ العمل منذ عدِّة سنوات في شركة (لن أسميها هنا)، والتي تستطيع أن تطلب منها إنشاء أي شيء غريب يمكن تخيله، وستصنعه لك خلال فترةٍ وجيزة.
</p>

<p>
	كان للشركة هامش ربحٍ كبير، وتجني أموالًا طائلة، وتعلمتُ الكثير عن إدارة الأعمال منها، لكنني تعلمتُ أيضًا بعض الأمور عن الأنظمة.
</p>

<p>
	كانت واجهة موقع الشركة الإلكتروني معقدةً! ولهذا السبب بدأ موقع الشركة في بدايات 2000 بالتحول إلى تطبيقٍ ذي صفحةٍ واحدة، حتى قبل انتشار فكرة التطبيقات ذات الصفحة الواحدة (single page application).
</p>

<p>
	كانت شيفرات JavaScript التي تشغل موقعهم معقدةً جدًا، وكانوا نادرًا ما يوظفون مبرمجين، واختاروا إطار عمل YUI بدلًا من jQuery لأنه كان شائعًا في تلك الفترة، ثم اشتقوا (fork) شيفرة YUI مما جعل التعامل معها وصيانتها أمرًا صعبًا جدًا. ولسببٍ أجهله، كانوا يكتبون شيفرات JavaScript بشكلٍ شبيهٍ بشيفرات Visual Basic.
</p>

<p>
	كانوا أيضًا يستعملون نظامًا لإدارة الإصدارات (version control system) من الثمانينات الذي كانت آلية حماية الملفات من التعديل فيه هي قفلها (file locks) والتي تستطيع بسهولة تجاوزها.
</p>

<p>
	سكربت البناء الذي كانوا يستعملونه هو شخصٌ اسمه Ed، فلتحويل الشيفرة إلى الخادوم الإنتاجي سيكون عليك أن تطبع قائمةً بالملفات التي عدَّلتَها وتسلمها لذاك الشخص، ثم سيبحث عن تلك الملفات وينسخها يدويًا إلى كل خادوم على حدة.
</p>

<p>
	كان السند الخلفي (<a href="https://academy.hsoub.com/programming/general/%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A9-%D8%A7%D9%84%D8%AE%D9%84%D9%81%D9%8A%D8%A9-backend-web-development/" rel="">backend</a>) للموقع هو حاسوبٌ قديمٌ يُشغِّل برمجيات مكتوبة في سبعينيات القرن الماضي، وكانت تُحدَّث بيئة التطوير المشتركة يدويًا من قِبل المطورين، متى أرادوا ذلك.
</p>

<p>
	إذا كنتَ تضحك الآن على حالهم وتظن أن هؤلاء الأشخاص أغبياء، فأظن أنَّ الوقتَ مناسبٌ لأشير إلى أنهم لم يعانوا من انقطاعاتٍ في الخدمة، وكانوا يُصدرون ميزاتٍ جديدة دوريًّا، ويجنون أموالًا طائلة تزداد عامًا بعد عامًا. لذا أظن أنهم يضحكون الآن خلال طريقهم إلى البنك ليستلموا أرباحهم.
</p>

<p>
	هل تتلقى أجرًا لقاء كتابتك للشيفرات؟ إذًا أنت تعمل لدى شركة. وعندما تقرر الشركة كيف تُنفِق ميزانية المطورين، فلن يكون منطقيًا أن تنفق مالًا لكتابة البرمجيات «بالطريقة الصحيحة». الفكرة التي أحاول إيصالها هنا هي أنَّ حال الشركة السابقة قد يبدو بائسًا بالنسبة إلى مطوري البرمجيات، لكنه منطقيٌ جدًا وجيد بالنسبة إلى أصحاب تلك الشركة الذين يهتمون بالربح.
</p>

<p>
	استخدام إطار عمل JavaScript قد لا يكون خيارًا استراتيجيًا للشركات حتى لو كان حالها سيئًا كالشركة التي نتحدث عنها.
</p>

<p>
	إذًا، كيف يجب أن تتابع الشركة السابقة بتطوير برمجياتها؟ كيف ستقرر الشركة أنها بحاجة إلى استخدام إطار عمل؟ شرحتُ سابقًا في مقالة «<a href="https://academy.hsoub.com/programming/javascript/%D9%84%D9%85%D8%A7%D8%B0%D8%A7-%D9%8A%D8%AF%D9%81%D8%B9%D9%86%D8%A7-%D8%A7%D9%84%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A8%D9%84%D8%BA%D8%A9-javascript-%D8%A5%D9%84%D9%89-%D8%AD%D8%A7%D9%81%D8%A9-%D8%A7%D9%84%D8%AC%D9%86%D9%88%D9%86-r446/" rel="">لماذا يدفعنا التطوير بلغة JavaScript إلى حافة الجنون!</a>» أنَّ من غير المنطقي البدء بتطوير البرمجيات انطلاقًا من إطار عمل. لنفترض وجود شيءٍ شبيهٍ بإطار Angular عند نشأة الشركة السابقة؛ فهل كان عليهم استخدام إطار عمل؟ هل يجب عليهم استخدام إطار عمل في هذه الفترة؟
</p>

<p>
	عندما تختار الشركة إطار عمل لتستعمله لتطوير برمجياتها، فهنالك كلف ومخاطر:
</p>

<p>
	<strong>- ماذا لو اختفى دعم إطار العمل خلال خمس سنوات؟</strong>
</p>

<p>
	هل يمكن أن تتحمل الشركة عبء صيانة إطار العمل بنفسها؟ هل يتوافر في فريق العمل أشخاصٌ لهم خبرات في هذا المجال؟ الجواب هو النفي لأغلبية الشركات، ولا نُغفِل أنَّ الكثير من <a href="https://academy.hsoub.com/programming/general/%D8%A5%D8%B7%D8%A7%D8%B1-%D8%B9%D9%85%D9%84-framework/" rel="">أطر العمل Frameworks</a> تختفي فجأةً. عليك أن تجري مع التيار وتخمِّن إن كانت الزيادة في الإنتاجية الآتية من اختيار إطار عمل تستحق الوقت والكلفة اللازمة للتحويل إلى إطارٍ آخر لاحقًا، أو أنَّها تستحق كلفة التعامل مع برمجيات غير مدعومة لسنوات في نفس الوقت الذي تحاول فيه توفير ميزانية كافية للتحويل إلى إطارٍ جديد.
</p>

<p>
	إذا كانت شيفرات برمجيتك قليلة نسبيًا وكنت تعمل في شركة وتحذف كميةً لا بأس بها من الشيفرات وتُعيد كتابتها (كثير منا يفعل ذلك لكنهم لا يعترفون)، فأرى أنَّ من المناسب استعمال إطار عمل.
</p>

<p>
	أما لو كانت شيفرات برمجيتك كثيرة جدًا، وكنت تنظر إلى خطتك التي وضعتها للسنوات الخمسة القادمة ورأيتها مليئةً بالميزات الجديدة التي ستكوِّن جزءًا أساسيًا من شركتك، فإن اختيار إطار عمل الذي سينتهي دعمه خلال خمسة سنوات هو رهانٌ خاسر، والطريقة الوحيدة التي ستجعلك تختار واحدًا هي التفكير بأجوبةٍ للأسئلة المتبقية …
</p>

<p>
	<strong>- كم ستخسر من إنتاجية مطوريك حتى يتعلموا إطار العمل الجديد؟</strong>
</p>

<p>
	إذا كنت تنتقل إلى إطارٍ وليكن Angular (وما لم توظِّف مطورين يعرفون Angular من قبل ويلمّون بأحدث المعلومات) فستنفق مالًا لتدريب فريق التطوير وسيضيّع المطورون الأشهر القادمة يسألون «كيف أفعل ذلك في Angular؟» حتى لو كانوا يفعلون نفس الأمر تمامًا باستخدام jQuery وشيفرات JavaScript البسيطة دون أدنى تفكير.
</p>

<p>
	<strong>- هل يمكننا بناء هذه الميزة التي تجعلنا نجني مالًا أكثر بنفس مقدار الوقت اللازم لتعلم إطار العمل؟</strong>
</p>

<p>
	الجواب لأغلبية الشركات الربحية هو «نعم».
</p>

<p>
	<strong>- هل سيسمح لنا إطار العمل بجني المزيد من المال بجعلنا نُنشِئ الميزات الجديدة بوتيرة أسرع في المستقبل؟</strong>
</p>

<p>
	نظريًا: هذه هي الفائدة المرجوة من إطار العمل. إذ ستحصل على فائدة أكبر من إطار العمل عندما يكون فريقك كبيرًا، وشيفرات مشروعك كثيرة، وتريد تسريع وتيرة تطوير الميزات الجديدة. لكن لاحظ أنَّك تستطيع تطوير بعض البرمجيات بسهولة ولن تستفيد فيها من التحول إلى إطار عمل.
</p>

<p>
	حسنًا، ربما تظن أنَّ هذا قرارٌ صعبٌ، إلا أنه في الواقع عكس ذلك لأغلبية الشركات.
</p>

<p style="text-align: center;">
	<img alt="use-a-framework-chart.png" class="ipsImage ipsImage_thumbnailed" data-fileid="23083" data-unique="607qnl17s" src="https://academy.hsoub.com/uploads/monthly_2017_05/use-a-framework-chart.png.76f023e432e3dac2b02e1d1334022a21.png">
</p>

<p>
	- الشركات الصغيرة وسريعة التغيرات تقع في الزاوية العليا اليسرى من المخطط السابق، فإذا كانت شيفرات برنامجك تتغير بسرعة فلن يكون من الخطر التغيير إلى إطار عمل آخر. فلو كنت تضيف الميزات يمنةً ويسرةً لأنك لم تعلم أيها يجني مالًا بعد، فلن تهتم إن «مات» إطار العمل الذي تستخدمه، لأنك ستحذف تلك الميزات والأجزاء من الشيفرات على أيّة حال.
</p>

<p>
	إذا كانت إنتاجيتك أكبر عندما تستعمل إطار عمل، وكنت تعمل لدى شركةٍ ناشئةٍ فسأقول أنَّ من الصواب استعمال إطار عمل، مع الأخذ بالحسبان أنَّ أغلبية الأشخاص تقل إنتاجيتهم عندما يستعملون إطار عمل لكنهم لا يعترفون بذلك.
</p>

<p>
	- تتواجد الشركات الصغيرة وذات معدل التغيير البطيء في الطرف السفلي اليساري من المخطط، وتكون إما شركات صغيرة تقليدية التي لا تُمثِّل البرمجيات مكوِّنًا أساسيًا من طريقة عملها، أو شركات البرمجيات الصغيرة.
</p>

<p>
	إذا كنت مبرمجًا تعمل لدى شركة صغيرة، فلا تستعمل إطار Angular أو React أو غيرهما. وإنما استخدم المكتبات المستقرة والثابتة والتي تعمل على جميع المتصفحات. فلو كنت تعمل في شركةٍ صغيرةٍ، فأرى أنَّ مخاطر استعمال إطار عمل تفوق ميزاته.
</p>

<p>
	- الشركات الكبيرة وذات معدل التغيير السريع تتواجد في القسم العلوي الأيمن من المخطط، وهي الشركات التي تكون البرمجيات مكوِّنًا أساسيًا فيها، أي أنهم يضيفون الميزات كثيرًا ويحذفون أجزاءً كبيرةً من الشيفرات ويعيدون كتابتها (حتى لو لم يعترفوا بذلك)، ولديهم فرق برمجية كبيرة، والميزات الجديدة التي يُضيفونها ستدر عليهم مالًا. لذا من المنطقي أن يدرِّبوا فِرَق البرمجة عندهم لاستعمال إطار عمل، لكي يبدأ الجميع من نفس المكان ولتُكتَب الميزات بوتيرة أسرع.
</p>

<p>
	إذا كانت شركتك ذات دخلٍ كبير، فستقل مخاطر فقدان دعم إطار العمل مع مرور الزمن، لأنك عندما كنت تختار ما هو إطار العمل الذي ستعمل عليه فستأخذ بالحسبان الدعم الطويل له. أما لو كنت تعمل في شركةٍ كبيرةٍ وتجني أموالًا طائلة وكانت البرمجيات من أساس عملك، فمن المنطقي أن تكتب إطار عمل خاص بك مثل Facebook و Google …
</p>

<p>
	- الشركات الكبيرة وذات معدل التغيير البطيء تقع في الركن السفلي اليميني من المخطط. وتنتمي الشركة التي تحدثنا عنها في بداية المقالة إلى هذا النوع، ولن يكون الخيار الصائب واضحًا هنا. فليس مجال عمل الشركة هو البرمجيات، لكن البرمجيات هي جزءٌ أساسيٌ نظام عمل الشركة. لن تتغير الشركة بسرعة، لكن الميزات الجديدة ستساعد الزبائن بشراء المزيد من المنتجات. مثاليًا، يمكنك أن تبني على إطار عمل الذي سيبقى حوالي 50 سنة، وهذا أمرٌ معقولٌ بالنسبة إلى شركةٍ تستعمل برمجيات وشيفرات عمرها 40 سنة. لكن هذا ليس موجودًا، لذا قد تفكر ببناء إطار عمل خاص بك، لأنك ستتأكد أنك لن تقع في فخ أطر العمل الميتة بعد 10 سنوات. لذا يجب أن تنشئ كل شيء من الصفر، وسترى أنَّ نفقات إنشاء ذلك قليلةٌ مقارنةً بالربح خلال 50 سنة …
</p>

<p>
	إذًا، هل يجب أن تنتقل الشركة إلى إطار عمل؟ لا يوجد جواب سهل! فعندما كنتُ مطورًا أعمل عندهم وكنت أفكر عن البرمجيات فقط، فكان الجواب الجلي بالنسبة لي هو: بالطبع يجب أن ينتقلوا لاستخدام Angular! لكن عندما بدأتُ شركتي الخاصة، فأصبحتُ أرى البرمجيات من زاويةٍ أخرى، لذا لن يكون الخيار سهلًا.
</p>

<p>
	توقف برهةً وفكِّر بعمق قبل الالتزام بإطار عمل، وإذا كنتَ صاحب قرار التحول إلى إطار عمل في حال استعملتك الشركة كمستشار، فأسدِ خدمةٍ إلى الشركة، وانزع عنك نظارات المبرمج، وضع نظارات مدير الأعمال.
</p>

<p>
	ترجمة -وبتصرّف- للمقال <a href="http://www.planningforaliens.com/blog/2016/06/09/when-to-use-a-js-framework/" rel="external nofollow">Should You Ever Use a JS Framework?</a>‎ لصاحبه Sean Fioritto
</p>
]]></description><guid isPermaLink="false">477</guid><pubDate>Wed, 03 May 2017 21:01:00 +0000</pubDate></item><item><title>&#x644;&#x645;&#x627;&#x630;&#x627; &#x64A;&#x62F;&#x641;&#x639;&#x646;&#x627; &#x627;&#x644;&#x62A;&#x637;&#x648;&#x64A;&#x631; &#x628;&#x644;&#x63A;&#x629; JavaScript &#x625;&#x644;&#x649; &#x62D;&#x627;&#x641;&#x629; &#x627;&#x644;&#x62C;&#x646;&#x648;&#x646;</title><link>https://academy.hsoub.com/programming/javascript/%D9%84%D9%85%D8%A7%D8%B0%D8%A7-%D9%8A%D8%AF%D9%81%D8%B9%D9%86%D8%A7-%D8%A7%D9%84%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A8%D9%84%D8%BA%D8%A9-javascript-%D8%A5%D9%84%D9%89-%D8%AD%D8%A7%D9%81%D8%A9-%D8%A7%D9%84%D8%AC%D9%86%D9%88%D9%86-r446/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_04/main.png.1272a8d9e10f1d3f7d474248fdfe7e14.png" /></p>

<p>
	<a id="____JavaScript____0" rel=""></a>أداة البناء Grunt أو Gulp، مكتبة require.js، ‏browserify، الإصدار السادس من ES، المفسرات، أطر عمل React و Angular و Amber، التعابير المغلقة (closures)، سلسلة prototype. <em>ارتفاع في ضغط الدم يؤدي إلى سكتة دماغية</em>.<br>
	حسنًا، تطوير الويب أمرٌ ممتع جدًا، لكن JavaScript مروعة!<br>
	تجد نفسك منسجمًا تمامًا مع جميع جوانب تطوير الويب، لكن عندما يأتي الأمر إلى JavaScript فستشعر أنَّ جزءًا كبيرًا من المعلومات الأساسية ينقصك بينما يعرفه الآخرون، والذي سيؤدي إلى جعلهم يفهمون سكربتات JavaScript.<br>
	نعم، الحقيقة هي أنَّك تفتقد بالفعل إلى بعض القطع؛ لكن هذا لا يعني أنَّ التوجه الحالي لتطوير الواجهات الأمامية ليس مجنونًا!<br>
	اطمئن، فأنت لستَ بمفردك، لذا اسحب كرسيًا واجلس، وجهِّز نفسك لكتابة تطبيق JavaScript.<br>
	أوّل خطوة هي ضبط بيئة التطوير المحلية، لذا اتخذ قرارك: هل ستستخدم Gulp، أم Grunt، لا! سأستعمل سكربتات NPM.<br>
	هل أستعمل Webpack أم Browserify أم Require.js؟ هل أتخذ قرارًا مصيريًا بالانتقال إلى الإصدار السادس من ES؟ أليس ضروريًا أن أضع مرجعًا عن أمراض القلب بجواري؟<br>
	كيف سأنظِّم اختبار الشيفرات؟ هل من إطارِ عملٍ تنصحني به؟ أليس من الأفضل تشغيل الاختبارات من سطر الأوامر، لنستعمل إذًا PhantomJS؟<br>
	مع أي إطارٍ أذهب: Angular أم React؟ ربما Ember؟ ماذا عن Backbone؟<br>
	ربما قرأتَ بعض صفحات توثيق React ووجدتَ فيها أنَّ «Redux هو حاويةٌ ذاتُ حالةٍ قابلةٍ للتوقع لتطبيقات JavaScript» وبدت على وجهك أمارات الرضى، فمن المؤكد أنَّك ستحتاج إلى هذه الميزة العظيمة، بغض النظر عن أنَّك لم تفهم حرفًا من شرحها.<br>
	السؤال الآن هو: لماذا أصبح تطوير تطبيقات JavaScript أمرًا يدفع إلى الجنون؟!<br>
	دعني أساعدك لفهم سبب ذلك. لنبدأ بمثالٍ بسيطٍ ثم سنستعرض صورًا جميلةً توضِّح وجهة نظري.<br>
	هذا تطبيق «Hello, World!‎» مكتوبٌ باستخدام React:
</p>

<pre>
 </pre>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8503_7">
<span class="com">// main.js</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> </span><span class="typ">React</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'react'</span><span class="pun">);</span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> </span><span class="typ">ReactDOM</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> require</span><span class="pun">(</span><span class="str">'react-dom'</span><span class="pun">);</span><span class="pln">

</span><span class="typ">ReactDOM</span><span class="pun">.</span><span class="pln">render</span><span class="pun">(</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Hello</span><span class="pun">,</span><span class="pln"> world</span><span class="pun">!&lt;/</span><span class="pln">h1</span><span class="pun">&gt;,</span><span class="pln">
  document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'example'</span><span class="pun">)</span><span class="pln">
  </span><span class="pun">);</span></pre>

<p>
	لم ننتهِ منه بعد:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8503_9">
<span class="pln">$ npm install </span><span class="pun">--</span><span class="pln">save react react</span><span class="pun">-</span><span class="pln">dom babelify babel</span><span class="pun">-</span><span class="pln">preset</span><span class="pun">-</span><span class="pln">react
$ browserify </span><span class="pun">-</span><span class="pln">t </span><span class="pun">[</span><span class="pln"> babelify </span><span class="pun">--</span><span class="pln">presets </span><span class="pun">[</span><span class="pln"> react </span><span class="pun">]</span><span class="pln"> </span><span class="pun">]</span><span class="pln"> main</span><span class="pun">.</span><span class="pln">js </span><span class="pun">-</span><span class="pln">o bundle</span><span class="pun">.</span><span class="pln">js</span></pre>

<p>
	هنالك عدِّة خطوات ناقصة هنا، مثل تثبيت مكتبة browserify أو ما الذي عليك فعله لتشغيل الصفحة في المتصفح، إذ لا يبدو أنَّ ما سبق سيُنشِئ صفحة ويب قادرة على فعل أيّ شيء!<br>
	بعد أن تنتهي من إنجاز ما سبق، فستجد ملفًا يدعى <code>bundle.js</code> يحتوي على تطبيق «Hello, World!‎» السابق المكتوب بمكتبة React والذي يضم حوالي 19374 سطرًا برمجيًا، وكل ما فعلتَه هو تثبيت browserify و babelify و react-dom، التي «تزن» آلاف الأسطر البرمجية.<br>
	هذه صورة تعبيرية عن برنامج «Hello, World!‎» في React:
</p>

<p style="text-align: center;">
	<img alt="tweet.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="22372" data-unique="ds8x1d57j" src="https://academy.hsoub.com/uploads/monthly_2017_04/tweet.jpg.28ba86c157a94034c7789d77562fc3fc.jpg"><br><a href="https://twitter.com/thomasfuchs/status/708675139253174273/photo/1?ref_src=twsrc%5Etfw" rel="external nofollow"><img alt="1_twitter_icon.png" class="ipsImage ipsImage_thumbnailed" data-fileid="22373" data-pin-nopin="true" data-unique="edgv5tj0g" src="https://academy.hsoub.com/uploads/monthly_2017_04/1_twitter_icon.png.4522b1591e351e5aec5a4b8876baf1e6.png" style="width: 25px; height: auto;"></a>
</p>

<p>
	حسنًا، هذا تطبيق «Hello, World!‎» باستخدام JavaScript دون مكتبات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8503_11">
<span class="pun">&lt;!</span><span class="pln">DOCTYPE html</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">html lang</span><span class="pun">=</span><span class="str">"en"</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;</span><span class="pln">head</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">meta charset</span><span class="pun">=</span><span class="str">"utf-8"</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">meta name</span><span class="pun">=</span><span class="str">"viewport"</span><span class="pln"> content</span><span class="pun">=</span><span class="str">"width=device-width"</span><span class="pln"> </span><span class="pun">/&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">title</span><span class="pun">&gt;</span><span class="typ">Hello</span><span class="pln"> </span><span class="typ">World</span><span class="pun">&lt;/</span><span class="pln">title</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">head</span><span class="pun">&gt;</span><span class="pln">

  </span><span class="pun">&lt;</span><span class="pln">body</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">div id</span><span class="pun">=</span><span class="str">"container"</span><span class="pun">&gt;&lt;/</span><span class="pln">div</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">
     document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">onload </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(){</span><span class="pln">
       </span><span class="kwd">var</span><span class="pln"> container </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">"container"</span><span class="pun">);</span><span class="pln">
       container</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">=</span><span class="pln"> </span><span class="str">'&lt;h1&gt;"Hello, world!"&lt;/h1&gt;'</span><span class="pun">;</span><span class="pln">
     </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">&lt;/</span><span class="pln">script</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">body</span><span class="pun">&gt;</span><span class="pln">
  </span><span class="pun">&lt;/</span><span class="pln">html</span><span class="pun">&gt;</span></pre>

<p>
	هذا كل ما في الأمر! 18 سطر برمجي (يمكن اختصارها إلى أقل من ذلك)، التي تستطيع نسخها ولصقها في ملفٍ باسم <code>index.html</code> وتنقر نقرتين عليه مما يفتحه في متصفحك. يا للبساطة!<br>
	إذا كنتَ تفكِّر في هذه اللحظة «أليس إطار React يفعل أكثر من ذاك المثال البسيط الذي كتبته، والذي لا يرقى أن يكون تطبيق JavaScript» فأنت مصيبٌ (تقريبًا)، وعلى بعد خطوة واحدة من فهمك لماذا كل هذا التعقيد. انظر إلى هذه الصورة:
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="22370" href="https://academy.hsoub.com/uploads/monthly_2017_04/bell_curve.png.2ad52e0bca2a4cfd024f031ae0441a51.png" rel=""><img alt="bell_curve.png" class="ipsImage ipsImage_thumbnailed" data-fileid="22370" data-unique="234eu77x9" src="https://academy.hsoub.com/uploads/monthly_2017_04/bell_curve.thumb.png.9c9d1d9288a60ebe4661eb3506848bbb.png"></a>
</p>

<p>
	أغلبية تطبيقات JavaScript التي ستعمل عليها ستقع في مكانٍ ما في منتصف المنحني الجرسي (bell curve) السابق. وإذا كنتَ في منتصف المنحني السابق وبدأت تطبيقًا بالاعتماد على React فسوف ينتهي بك المطاف بهندسة تطبيقك زيادةً عن اللزوم من بدايته.<br>
	وهذا هو سبب تعقيد تطوير تطبيقات JavaScript، لأنَّ غرض أغلبية الأدوات التي تظن أنَّك بحاجةٍ إليها هو حلّ المشاكل التي لن تتعرض إليها بتاتًا.
</p>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="22371" href="https://academy.hsoub.com/uploads/monthly_2017_04/bell_curve_2.png.3dbd0cd90600e893bb2445074eabeab4.png" rel=""><img alt="bell_curve_2.png" class="ipsImage ipsImage_thumbnailed" data-fileid="22371" data-unique="bp44egl0w" src="https://academy.hsoub.com/uploads/monthly_2017_04/bell_curve_2.thumb.png.5bc3e532a40c7bea2cf6330d128861e8.png"></a>
</p>

<p>
	أصبحت حالة تطوير تطبيقات JavaScript في الآونة الأخيرة معقدةً ومربكةً لأنَّ الجميع يبالغون في هندسة تطبيقاتهم دون أن يدركوا ذلك.<br>
	إذًا، كيف يجب أن نبدأ بتطوير تطبيق JavaScript؟ هل علينا استخدام مكتبة شبيهة بمكتبة React أو Angular؟ هل يجب أن نستخدم مدير للحزم؟ ماذا يفترض علينا أن نفعل إذا لم نستخدمهما؟ هل كتابة الاختبارات ضرورية؟ هل علينا أصلًا توليد شيفرات HTML عبر JavaScript؟ هذه هي الأسئلة التي يجب أن تسألها لنفسك قبل أن تبدأ بمجموعة ضخمة من أدوات التطوير.<br>
	عندما تبدأ بتطوير تطبيق JavaScript فمن المهم أن تختار نقطةً في المنحني الجرسي في المكان الذي تظن أنَّ من المرجح أن يصله تطبيقك في المستقبل من ناحية التعقيد.<br>
	لن أكذب عليك، فعل ذلك ليس سهلًا ويحتاج خبرةً، لكن هنالك منطقةٌ كبيرة يمكنك أن تبدأ منها أغلبية تطبيقات JavaScript: استعمل مكتبة jQuery مع قوالب لصفحات الواجهة الأمامية مع أداة بناء بسيطة لجمع الملفات وتصغيرها (بفرض أنَّ إطار العمل الذي تستعمله لتطوير السند الخلفي [backend] لا يفعل ذلك تلقائيًا).<br>
	إذا أردتَ أن تتعلم كيفية هيكلة تطبيق JavaScript بطريقةٍ صحيحة، فعليك أن تبدأ بفهم كيف ومتى ولماذا تستخدم إطار عمل أو حزمة npm أو إصدار ES6 أو متى تكتب اختبارات أو هل عليك جعل الاختبارات تعمل محليًا أو في متصفح، ثم سيأتي دور بقية الأسئلة وحلّ بقية المشاكل.<br>
	إن أردتَ أن تملأ الفجوات الموجودة في معلوماتك حول تطوير JavaScript وأن تتجنّب الشعور بأنّك تبالغ في تصميم تطبيق JavaScript فحاول أن تتابع ما نطرحه هنا في قسم البرمجة في أكاديمية حسوب.<br>
	ترجمة -وبتصرّف- للمقال <a href="http://www.planningforaliens.com/blog/2016/04/11/why-js-development-is-crazy/" rel="external nofollow">Why JavaScript Development is Crazy</a> لصاحبه Sean Fioritto
</p>
]]></description><guid isPermaLink="false">446</guid><pubDate>Sun, 02 Apr 2017 21:07:28 +0000</pubDate></item><item><title>&#x62A;&#x623;&#x62B;&#x64A;&#x631;&#x627;&#x62A; &#x627;&#x644;&#x62A;&#x645;&#x631;&#x64A;&#x631; &#x641;&#x64A; &#x635;&#x641;&#x62D;&#x627;&#x62A; &#x627;&#x644;&#x648;&#x64A;&#x628; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; Javascript &#x648;CSS&#x2013; &#x627;&#x644;&#x62C;&#x632;&#x621; &#x627;&#x644;&#x62B;&#x627;&#x644;&#x62B;</title><link>https://academy.hsoub.com/programming/javascript/%D8%AA%D8%A3%D8%AB%D9%8A%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D9%85%D8%B1%D9%8A%D8%B1-%D9%81%D9%8A-%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-javascript-%D9%88css%E2%80%93-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%AB%D8%A7%D9%84%D8%AB-r475/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_04/33.jpg.a6d5b1274adcc321876ff2b28be3284f.jpg" /></p>

<p id="تأثيرات-التمرير-في-صفحات-الويب-باستخدام-javascript-وcss-الجزء-الثالث">
	أهلًا بك في هذه السلسلة التي تتحدث عن تأثيرات التمرير (Scrolling Effects)، سنستعرض في هذه السلسلة عددٌ من تأثيرات التمرير وسنشرح آلية عملها وسنجرِّبها عمليًا.<br>
	يمكننا الاستفادة من الحدث <code>scroll</code> في JavaScript لإجراء تأثيرات عند تمرير صفحة الويب؛ لكن إن فعلنا ذلك دون إتقان فالنتيجة كارثية، أما إذا أحسنا صنعنا فيمكن لتأثيرات التمرير أن تبهر الزوار وتشعرهم أنَّ موقعك مميز.<br>
	تحدثنا في المقالتين السابقتين عن التأثيرات الآتية:
</p>

<ul>
<li>
		إخفاء صورة خلفية تدريجيًا عند التمرير
	</li>
	<li>
		توضيح الصورة عند التمرير
	</li>
	<li>
		تدوير العناصر عند التمرير
	</li>
	<li>
		تأثير اختلاف المظهر parallax
	</li>
	<li>
		إظهار صورة الخلفية عند التمرير باستخدام CSS فقط
	</li>
	<li>
		تمرير سلس للصفحة
	</li>
	<li>
		تطبيق تأثير عدم الوضوح على المحتوى خلف شريط الانتقال
	</li>
</ul>
<p>
	وسنشرح في هذه المقالة (الثالثة) طريقة إنشاء:
</p>

<ul>
<li>
		عنصر قابل للتمرير مع إمكانية وصول مخصصة من لوحة المفاتيح
	</li>
	<li>
		تأثير غروب الشمس باستخدام SVG
	</li>
	<li>
		إظهار فيديو في الخلفية
	</li>
	<li>
		صور متحركة بتأثير parallax باستخدام CSS 3D و JavaScript
	</li>
</ul>
<p>
	سأقدِّم لك في بداية كل قسم رابطًا لتجربة المثال تجربةً حيةً على المتصفح. سيسهل عليك كثيرًا أن تفهم الشرح والشيفرات بعد تجربتك للتأثير.
</p>

<h2 id="عنصر-قابل-للتمرير-مع-إمكانية-وصول-مخصصة-من-لوحة-المفاتيح">
	عنصرٌ قابلٌ للتمرير مع إمكانية وصول مخصصة من لوحة المفاتيح
</h2>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="22955" href="https://academy.hsoub.com/uploads/monthly_2017_04/1-CustomScrollingElementWithKeyboardAccessibility.jpg.b974c150b248a84a6fb9b0dc6b76e743.jpg" rel=""><img alt="1-CustomScrollingElementWithKeyboardAccessibility.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="22955" data-unique="w2necuujy" src="https://academy.hsoub.com/uploads/monthly_2017_04/1-CustomScrollingElementWithKeyboardAccessibility.thumb.jpg.3eecd20d51cf468717fb33376d180d53.jpg"></a>
</p>

<p>
	(<a href="https://codepen.io/anon/pen/VKmoxZ" rel="external nofollow">تجربة حية</a>)<br>
	كقاعدة عامة، إخفاء المعلومات المهمة داخل عنصر قابل للتمرير هي فكرةٌ سيئة، لكنه تُستعمَل عادةً من المصممين لأنها تبدو «ذات مظهرٍ جيد» بدلًا من التفكير حول قابلية استخدامها؛ لكن هنالك حالات يمكن فيها من الضروري فعل ذلك، وعندئذٍ يجب أن تكون الروابط داخل تلك العناصر قابلةً للوصول عبر لوحة المفاتيح.
</p>

<h3 id="شيفرات-html-و-css-الأساسية">
	شيفرات HTML و CSS الأساسية
</h3>

<p>
	تقريبًا جميع العناصر يمكن أن تُضبَط لها الخاصية <code>overflow: scroll</code>، لذا لن يصعب علينا إنشاء شيفرة HTML. سأذكر في هذا المثال بعض الأماكن في أفريقيا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7416_11" style="">
<span class="pun">&lt;</span><span class="pln">ol id</span><span class="pun">=</span><span class="str">"scrolling-list"</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">li</span><span class="pun">&gt;&lt;</span><span class="pln">a href</span><span class="pun">=#&gt;&lt;</span><span class="pln">img src</span><span class="pun">=</span><span class="str">"tunisia.jpg"</span><span class="pln"> alt</span><span class="pun">&gt;</span><span class="typ">Tunisia</span><span class="pun">&lt;/</span><span class="pln">a</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">li</span><span class="pun">&gt;&lt;</span><span class="pln">a href</span><span class="pun">=#&gt;&lt;</span><span class="pln">img src</span><span class="pun">=</span><span class="str">"botswana.jpg"</span><span class="pln"> alt</span><span class="pun">&gt;</span><span class="typ">Botswana</span><span class="pun">&lt;/</span><span class="pln">a</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">li</span><span class="pun">&gt;&lt;</span><span class="pln">a href</span><span class="pun">=#&gt;&lt;</span><span class="pln">img src</span><span class="pun">=</span><span class="str">"south-africa.jpg"</span><span class="pln"> alt</span><span class="pun">&gt;</span><span class="typ">South</span><span class="pln"> </span><span class="typ">Africa</span><span class="pun">&lt;/</span><span class="pln">a</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">li</span><span class="pun">&gt;&lt;</span><span class="pln">a href</span><span class="pun">=#&gt;&lt;</span><span class="pln">img src</span><span class="pun">=</span><span class="str">"kenya.jpg"</span><span class="pln"> alt</span><span class="pun">&gt;</span><span class="typ">Kenya</span><span class="pun">&lt;/</span><span class="pln">a</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">li</span><span class="pun">&gt;&lt;</span><span class="pln">a href</span><span class="pun">=#&gt;&lt;</span><span class="pln">img src</span><span class="pun">=</span><span class="str">"nigeria.jpg"</span><span class="pln"> alt</span><span class="pun">&gt;</span><span class="typ">Nigeria</span><span class="pun">&lt;/</span><span class="pln">a</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">li</span><span class="pun">&gt;&lt;</span><span class="pln">a href</span><span class="pun">=#&gt;&lt;</span><span class="pln">img src</span><span class="pun">=</span><span class="str">"tanzania.jpg"</span><span class="pln"> alt</span><span class="pun">&gt;</span><span class="typ">Tanzania</span><span class="pun">&lt;/</span><span class="pln">a</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">ol</span><span class="pun">&gt;</span></pre>

<p>
	ستعرض شيفرة CSS التي سنكتبها القائمةَ بارتفاعٍ معيّن، الخاصية <code>height</code> نفسها لن تؤثر على طريقة العرض، فالقاعدة العامة هي أنَّ المحتوى سيُعرَض دومًا حتى لو تجاوز حدود العنصر الحاوي له. إذا أردنا أن نعكس هذا السلوك، فعلينا القيام بخطواتٍ معيّنة، وفي هذه الحالة، سنضبط الخاصية <code>overflow-y: scroll</code> لنتيح إمكانية التمرير داخل القائمة. لاحظ استخدامنا للكلمة المحجوزة <code>currentcolor</code> وغيرها من الاختصارات التي تجعل عملية التطوير أسهل.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7416_11" style="">
<code class="hljs css"><span class="hljs-tag"><span class="pln">ol</span></span><span class="hljs-id"><span class="com">#scrolling-list</span></span><span class="com"> </span><span class="hljs-rules"><span class="com">{</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">font</span><span class="pun">-</span><span class="pln">size</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">0</span></span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">background</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-hexcolor"><span class="com">#333</span></span></span></span><span class="com">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">list</span><span class="pun">-</span><span class="pln">style</span><span class="pun">-</span><span class="pln">type</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> none</span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">padding</span><span class="pun">-</span><span class="pln">left</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">0</span></span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">height</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">230</span></span><span class="lit">px</span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">overflow</span><span class="pun">-</span><span class="pln">y</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> scroll</span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">font</span><span class="pun">-</span><span class="pln">weight</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">100</span></span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">color</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-hexcolor"><span class="com">#999</span></span></span></span><span class="com">;</span><span class="pln">
</span><span class="hljs-rule"><span class="pun">}</span></span></span><span class="pln">
</span><span class="hljs-tag"><span class="pln">ol</span></span><span class="hljs-id"><span class="com">#scrolling-list</span></span><span class="com"> </span><span class="hljs-tag"><span class="com">li</span></span><span class="com"> </span><span class="hljs-rules"><span class="com">{ </span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">border</span><span class="pun">-</span><span class="pln">bottom</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">1</span></span><span class="lit">px</span><span class="pln"> dashed</span></span></span><span class="pun">;</span><span class="pln"> 
</span><span class="hljs-rule"><span class="pun">}</span></span></span><span class="pln">
</span><span class="hljs-tag"><span class="pln">ol</span></span><span class="hljs-id"><span class="com">#scrolling-list</span></span><span class="com"> </span><span class="hljs-tag"><span class="com">li</span></span><span class="com"> </span><span class="hljs-tag"><span class="com">a</span></span><span class="com"> </span><span class="hljs-rules"><span class="com">{</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">font</span><span class="pun">-</span><span class="pln">size</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">1.2</span></span><span class="lit">rem</span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">text</span><span class="pun">-</span><span class="pln">decoration</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> none</span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">line</span><span class="pun">-</span><span class="pln">height</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">2</span></span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">color</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> currentcolor</span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">display</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> block</span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">transition</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="pun">.</span><span class="hljs-number"><span class="lit">4</span></span><span class="lit">s</span><span class="pln"> background</span></span></span><span class="pun">;</span><span class="pln">
</span><span class="hljs-rule"><span class="pun">}</span></span></span><span class="pln">
</span><span class="hljs-tag"><span class="pln">ol</span></span><span class="hljs-id"><span class="com">#scrolling-list</span></span><span class="com"> </span><span class="hljs-tag"><span class="com">li</span></span><span class="com"> </span><span class="hljs-tag"><span class="com">a</span></span><span class="com"> </span><span class="hljs-tag"><span class="com">img</span></span><span class="com"> </span><span class="hljs-rules"><span class="com">{</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">width</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">20</span></span><span class="pun">%</span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">vertical</span><span class="pun">-</span><span class="pln">align</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> top</span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">margin</span><span class="pun">-</span><span class="pln">right</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="pun">.</span><span class="hljs-number"><span class="lit">5</span></span><span class="lit">rem</span></span></span><span class="pun">;</span><span class="pln">
</span><span class="hljs-rule"><span class="pun">}</span></span></span></code></pre>

<p>
	عملية تخصيص شريط التمرير أصبحت محدودة: ففي وقتٍ سابقٍ كان متصفحا Internet Explorer و Firefox يستعملان مُحدِّدات CSS ‏(CSS selectors) لفعل ذلك، لكنهما أهملا دعمها لاحقًا. ما يزال بإمكاننا تخصيص شريط التمرير في المتصفحات التي تعتمد على المحرك Webkit، بسلسلة من المُحدِّدات الخاصية بهذا النوع من المتصفحات (والتي تُشبه تلك التي نستعملها لتخصيص حقل <code>range</code> للإدخال):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7416_11" style="">
<code class="hljs css"><span class="hljs-tag"><span class="pln">ol</span></span><span class="hljs-id"><span class="com">#scrolling-list</span></span><span class="hljs-pseudo"><span class="com">::-webkit-scrollbar</span></span><span class="com"> </span><span class="hljs-rules"><span class="com">{ </span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">background</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-hexcolor"><span class="com">#000</span></span></span></span><span class="com">; </span><span class="pln">
</span><span class="hljs-rule"><span class="pun">}</span></span></span><span class="pln">
</span><span class="hljs-tag"><span class="pln">ol</span></span><span class="hljs-id"><span class="com">#scrolling-list</span></span><span class="hljs-pseudo"><span class="com">::-webkit-scrollbar-thumb</span></span><span class="com"> </span><span class="hljs-rules"><span class="com">{</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">background</span><span class="pun">-</span><span class="pln">color</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-function"><span class="pln">hsl</span><span class="pun">(</span><span class="hljs-number"><span class="lit">33</span></span><span class="pun">,</span><span class="hljs-number"><span class="lit">100</span></span><span class="pun">%,</span><span class="hljs-number"><span class="lit">50</span></span><span class="pun">%)</span></span></span></span><span class="pun">;</span><span class="pln"> 
</span><span class="hljs-rule"><span class="pun">}</span></span></span></code></pre>

<p>
	في النهاية، سنُخصِّص حالة <code>‎:hover</code> للروابط وسنُخصِّص حالة <code>‎:focus</code> أيضًا بتجميعهما معًا وذلك لتوضيح ما هو الرابط الذي نُحدِّده عبر لوحة المفاتيح:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7416_11" style="">
<code class="hljs css"><span class="hljs-tag"><span class="pln">ol</span></span><span class="hljs-id"><span class="com">#scrolling-list</span></span><span class="com"> </span><span class="hljs-tag"><span class="com">li</span></span><span class="com"> </span><span class="hljs-tag"><span class="com">a</span></span><span class="hljs-pseudo"><span class="com">:hover</span></span><span class="com">,</span><span class="pln">
</span><span class="hljs-tag"><span class="pln">ol</span></span><span class="hljs-id"><span class="com">#scrolling-list</span></span><span class="com"> </span><span class="hljs-tag"><span class="com">li</span></span><span class="com"> </span><span class="hljs-tag"><span class="com">a</span></span><span class="hljs-pseudo"><span class="com">:focus</span></span><span class="com"> </span><span class="hljs-rules"><span class="com">{ </span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">background</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-hexcolor"><span class="com">#111</span></span></span></span><span class="com">; </span><span class="pln">
</span><span class="hljs-rule"><span class="pun">}</span></span></span></code></pre>

<h3 id="تحسين-قابلية-الوصول-باستخدام-javascript">
	تحسين قابلية الوصول باستخدام JavaScript
</h3>

<p>
	بافتراض أنَّ لديك إمكانية كاملة للتنقل باستخدام لوحة المفاتيح في متصفحك (أسهل متصفح لتجربة ذلك هو Chrome، إذ تتطلب بقية المتصفحات أن تضبط بعض الخيارات أولًا) وستجد أنَّك إذا ضغطتَ على زر TAB فستنتقل بين الروابط في السلسلة، فبعد أن تصبح داخل السلسلة ستتمكن من الانتقال إلى الأمام (أي إلى الروابط التالية) باستخدام TAB أو إلى الخلف (أي إلى الروابط السابقة) باستخدام SHIFT+TAB، وتتحكم أزرار الأسهم بتمرير العنصر. لا يوجد شيءٌ خاطئٌ في ما سبق، لكن في بعض الحالات سترغب بالسماح للمستخدم باستعمال أزرار الأسهم لاختيار العناصر في القائمة بدلًا من التمرير.<br>
	سنحتاج في البداية إلى تحديد بعض الكائنات باستخدام JavaScript:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7416_11" style="">
<code class="hljs matlab"><span class="kwd">var</span><span class="pln"> locales </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-transposed_variable"><span class="pln">document</span><span class="pun">.</span></span><span class="pln">getElementById</span><span class="pun">(</span><span class="hljs-string"><span class="str">'scrolling-list'</span></span><span class="pun">),</span><span class="pln">
listItems </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-transposed_variable"><span class="pln">locales</span><span class="pun">.</span></span><span class="pln">children</span><span class="pun">,</span><span class="pln">
allLnks </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Array</span><span class="pun">();</span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">for</span></span><span class="pln"> </span><span class="pun">(</span><span class="kwd">var</span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">i</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">;</span><span class="hljs-built_in"><span class="pln">i</span></span><span class="pun">&lt;</span><span class="hljs-transposed_variable"><span class="pln">listItems</span><span class="pun">.</span></span><span class="hljs-built_in"><span class="pln">length</span></span><span class="pun">;</span><span class="hljs-built_in"><span class="pln">i</span></span><span class="pun">++)</span><span class="pln"> </span><span class="hljs-cell"><span class="pun">{</span><span class="pln">
    allLnks</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> listItems</span><span class="pun">[</span><span class="pln">i</span><span class="pun">].</span><span class="pln">firstElementChild</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></span></code></pre>

<p>
	المتغير <code>listItems</code> يمثِّل العناصر المُشكِّلة للقائمة، بينما <code>allLnks</code> فهو مصفوفة للروابط الموجودة داخل عناصر القائمة. ولأننا وضعنا تلك العناصر داخل بعضها بعضًا فهذا سيجعل بقية السكربت معقدة قليلًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7416_11" style="">
<code class="hljs javascript"><span class="pln">locales</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="hljs-string"><span class="str">'keydown'</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">function</span></span><span class="hljs-params"><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span></span><span class="pln"> </span><span class="pun">{</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">var</span></span><span class="pln"> focusedElement </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">activeElement</span><span class="pun">,</span><span class="pln">
    index </span><span class="pun">=</span><span class="pln"> allLnks</span><span class="pun">.</span><span class="pln">indexOf</span><span class="pun">(</span><span class="pln">focusedElement</span><span class="pun">);</span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> </span><span class="pun">(</span><span class="pln">index </span><span class="pun">&gt;=</span><span class="pln"> </span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</span><span class="pun">.</span><span class="pln">keyCode </span><span class="pun">==</span><span class="pln"> </span><span class="hljs-number"><span class="lit">40</span></span><span class="pln"> </span><span class="pun">||</span><span class="pln"> e</span><span class="pun">.</span><span class="pln">keyCode </span><span class="pun">==</span><span class="pln"> </span><span class="hljs-number"><span class="lit">39</span></span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> </span><span class="pun">(</span><span class="pln">focusedElement</span><span class="pun">.</span><span class="pln">parentNode</span><span class="pun">.</span><span class="pln">nextElementSibling</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="hljs-keyword"><span class="kwd">var</span></span><span class="pln"> nextNode </span><span class="pun">=</span><span class="pln"> focusedElement</span><span class="pun">.</span><span class="pln">parentNode</span><span class="pun">.</span><span class="pln">nextElementSibling</span><span class="pun">.</span><span class="pln">firstElementChild</span><span class="pun">;</span><span class="pln">
                nextNode</span><span class="pun">.</span><span class="pln">focus</span><span class="pun">();</span><span class="pln">
            </span><span class="pun">}</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">else</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                listItems</span><span class="pun">[</span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">].</span><span class="pln">firstElementChild</span><span class="pun">.</span><span class="pln">focus</span><span class="pun">();</span><span class="pln"> 
            </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
        </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> </span><span class="pun">(</span><span class="pln">e</span><span class="pun">.</span><span class="pln">keyCode </span><span class="pun">==</span><span class="pln"> </span><span class="hljs-number"><span class="lit">38</span></span><span class="pln"> </span><span class="pun">||</span><span class="pln"> e</span><span class="pun">.</span><span class="pln">keyCode </span><span class="pun">==</span><span class="pln"> </span><span class="hljs-number"><span class="lit">37</span></span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> </span><span class="pun">(</span><span class="pln">focusedElement</span><span class="pun">.</span><span class="pln">parentNode</span><span class="pun">.</span><span class="pln">previousElementSibling</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                </span><span class="hljs-keyword"><span class="kwd">var</span></span><span class="pln"> previousNode </span><span class="pun">=</span><span class="pln"> focusedElement</span><span class="pun">.</span><span class="pln">parentNode</span><span class="pun">.</span><span class="pln">previousElementSibling</span><span class="pun">.</span><span class="pln">firstElementChild</span><span class="pun">;</span><span class="pln">
                previousNode</span><span class="pun">.</span><span class="pln">focus</span><span class="pun">();</span><span class="pln">
            </span><span class="pun">}</span><span class="pln"> </span><span class="hljs-keyword"><span class="kwd">else</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                locales</span><span class="pun">.</span><span class="pln">lastElementChild</span><span class="pun">.</span><span class="pln">firstElementChild</span><span class="pun">.</span><span class="pln">focus</span><span class="pun">();</span><span class="pln">
            </span><span class="pun">}</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">});</span></code></pre>

<p>
	أنشأنا دالةً لمعالجة الحدث <code>keydown</code> (الذي يُطلَق عندما يُضغَط على أحد الأزرار في لوحة المفاتيح) عندما يَحدُثُ داخل الكائن <code>locales</code>، لكننا نريد أن نُغيّر سلوك مفاتيح الأسهم إذا كان أحد عناصر القائمة مُركَّزًا عليه (focused)، وإلا فسنتحكّم بسلوك مفاتيح الأسهم من بداية تحمل الصفحة، وهذا ما سيمنع المستخدمين من التمرير في الصفحة باستخدامها.<br>
	لفعل ذلك سنتحقق من العنصر المُركَّز عليه حاليًا (عبر <code>document.activeElement</code>) وسنرى إن كان يُطابِق أحد عناصر مصفوفة الروابط التي أنشأناها، فإن طابق أحدها فسنتحقق إن كان الزر المضغوط مساوٍ لرمز السهم السفلي أو الأيمن، فإن كان كذلك فسيتم التحقق من وجود عنصرٍ يلي العنصرَ الحالي، فإن وجد فسيتم نقل التركيز إلى العنصر التالي، وإلا فسيتم التركيز على أوّل عنصر في القائمة.<br>
	الشيفرة الخاصة بتغيير سلوك السهم العلوي أو الأيسر مشابهة لما سبق، حيث سيُنقَل التركيز إلى العنصر الذي يسبق العنصر الحالي، وسيُنقَل التركيز إلى آخر رابط إن وصلنا إلى أعلى القائمة.
</p>

<h3 id="الخلاصة">
	الخلاصة
</h3>

<p>
	إذا فكّرتَ قليلًا بالسكربت وخططت له، فيمكنك إنشاء شريط تنقل جميل وقابل للوصول، وذلك بتطبيق ما تعلمته هنا لكن مع بعض التحسينات.
</p>

<h2 id="تأثير-غروب-الشمس-باستخدام-svg">
	تأثير غروب الشمس باستخدام SVG
</h2>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="22956" href="https://academy.hsoub.com/uploads/monthly_2017_04/2-ScrollingSVGSunset.jpg.60b1fc839fe0164658b132a9462d8bd3.jpg" rel=""><img alt="2-ScrollingSVGSunset.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="22956" data-unique="x0l2741y1" src="https://academy.hsoub.com/uploads/monthly_2017_04/2-ScrollingSVGSunset.thumb.jpg.3e3eb96f1e849b0d630bf475e09f7a9b.jpg"></a>
</p>

<p>
	(<a href="https://codepen.io/dudleystorey/pen/oLxKGv" rel="external nofollow">تجربة حية</a>)<br>
	الرسوميات التي تصوِّر الطبيعة مناسبةٌ جدًا لتأثيرات parallax، وعادةً تتحرك عناصر تلك الرسوميات شاقوليًا، وتستخدم عددًا هائلًا من صور PNG (التي لها شفافية) كطبقات.<br>
	وخطر ببالي أنَّه يمكن توظيف رسومات SVG كبديل ممتاز لما سبق: حيث أنَّ حجم الصورة صغيرٌ جدًا، ويمكن إعادة تلوين عناصرها أو تحريكهم كلًا على حدة كما هو ظاهر في <a href="https://codepen.io/dudleystorey/pen/oLxKGv" rel="external nofollow">هذا المثال</a>.
</p>

<h3 id="بناء-الهضبات-مستوية-السطح">
	بناء الهضبات مستوية السطح
</h3>

<p>
	تتألف الصورة من سلسلة من الهضبات مستوية السطح التي هي مسارات مغلقة (closed paths)، باستثناء الشمس التي هي دائرة مُنشَأة بعنصر <code>&lt;circle&gt;</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7416_11" style="">
<code class="hljs xml"><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">svg</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">id</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"arizona"</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">xmlns</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"http://www.w3.org/2000/svg"</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">viewBox</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"0 0 750 279"</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">circle</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">id</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"sun"</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">fill</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"#FFF7EB"</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">cx</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"655"</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">cy</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"128"</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">r</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"41.5"</span></span><span class="tag">/&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">path</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">fill</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"hsl(32, 89%, 75%)"</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">d</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"M750 ... "</span></span><span class="tag">/&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">path</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">fill</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"hsl(31, 74%, 71%)"</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">d</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"M745 ..."</span></span><span class="pln"> </span><span class="tag">/&gt;</span></span></code></pre>

<p>
	أنشأنا المسارات البعيدة أولًا، أي أنَّ أبعد هضبة ستُعرَّف في البداية، ثم تليها الأقرب فالأقرب.
</p>

<h3 id="السماء-والتدرجات">
	السماء والتدرجات
</h3>

<p>
	بدلًا من إنشاء عنصر <code>&lt;rect&gt;</code> للسماء، فسيتم ملء خلفية عنصر <code>&lt;svg&gt;</code> باستخدام CSS:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7416_11" style="">
<code class="hljs css"><span class="hljs-id"><span class="com">#arizona</span></span><span class="com"> </span><span class="hljs-rules"><span class="com">{ </span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">background</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-function"><span class="pln">hsl</span><span class="pun">(</span><span class="hljs-number"><span class="lit">47</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">100</span></span><span class="pun">%,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">86</span></span><span class="pun">%)</span></span></span></span><span class="pun">;</span><span class="pln">
</span><span class="hljs-rule"><span class="pun">}</span></span></span></code></pre>

<p>
	استخدام ألوان HSL (سواءً داخل شيفرات SVG أو عبر أنماط CSS) هو المفتاح الرئيسي لهذا التأثير، وذلك بتغير درجة السطوع (luminosity) لكل عنصر وذلك عند التمرير، وبذلك سنعطي انطباعًا بشروق أو غروب الشمس.<br>
	الجزء الصعب هو استخراج قيمة HSL لكل عنصر، ولفعل ذلك سأستخدم التعابير النمطية (regular expressions) في JavaScript، هذه الشيفرة تُعرِّف التعبير النمطي الذي سنستخدمه مع جمع بعض المعلومات عن عنصر SVG:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7416_11" style="">
<code class="hljs avrasm"><span class="kwd">var</span><span class="pln"> regex </span><span class="pun">=</span><span class="pln"> </span><span class="str">/hsl\((\d+),\s*([\d.]+)%,\s*([\d.]+)%\)/</span><span class="pun">,</span><span class="pln">
arizona </span><span class="pun">=</span><span class="pln"> document</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">getElementById</span></span><span class="pun">(</span><span class="hljs-string"><span class="str">"arizona"</span></span><span class="pun">),</span><span class="pln">
mesaLayers </span><span class="pun">=</span><span class="pln"> arizona</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">querySelectorAll</span></span><span class="pun">(</span><span class="hljs-string"><span class="str">"path"</span></span><span class="pun">),</span><span class="pln">
</span><span class="typ">SVGoffsettop</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> arizona</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">getBoundingClientRect</span></span><span class="pun">()</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">top</span></span><span class="pun">,</span><span class="pln">
vertHeight </span><span class="pun">=</span><span class="pln"> arizona</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">getBoundingClientRect</span></span><span class="pun">()</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">height</span></span><span class="pun">,</span><span class="pln">
sun </span><span class="pun">=</span><span class="pln"> document</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">getElementById</span></span><span class="pun">(</span><span class="hljs-string"><span class="str">"sun"</span></span><span class="pun">)</span><span class="hljs-comment"><span class="pun">;</span></span></code></pre>

<p>
	المتغير <code>mesaLayers</code> يضم جميع العناصر المُشكِّلة للهضبات معًا، وسيتم التعامل مع التمرير داخل دالة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7416_11" style="">
<code class="hljs avrasm"><span class="kwd">function</span><span class="pln"> scrollHandler</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">window</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">scrollY</span></span><span class="pln"> </span><span class="pun">&lt;</span><span class="pln"> vertHeight</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="typ">Array</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">prototype</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">forEach</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">call</span></span><span class="pun">(</span><span class="pln">mesaLayers</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">layer</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
        </span><span class="kwd">var</span><span class="pln"> layerFill </span><span class="pun">=</span><span class="pln"> layer</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">getAttribute</span></span><span class="pun">(</span><span class="hljs-string"><span class="str">"fill"</span></span><span class="pun">),</span><span class="pln">
        vertRoll </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">abs</span></span><span class="pun">(</span><span class="pln">window</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">scrollY</span></span><span class="pln"> </span><span class="pun">-</span><span class="pln"> vertHeight</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> vertHeight</span><span class="hljs-comment"><span class="pun">;</span></span><span class="pln">
        hslComponents </span><span class="pun">=</span><span class="pln"> layerFill</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">match</span></span><span class="pun">(</span><span class="pln">regex</span><span class="pun">)</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">slice</span></span><span class="pun">(</span><span class="hljs-number"><span class="lit">1</span></span><span class="pun">),</span><span class="pln">
        newLum </span><span class="pun">=</span><span class="pln"> parseFloat</span><span class="pun">(</span><span class="pln">hslComponents</span><span class="pun">[</span><span class="hljs-number"><span class="lit">2</span></span><span class="pun">])</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> vertRoll</span><span class="hljs-comment"><span class="pun">;</span></span><span class="pln">
        layer</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">style</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">fill</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">"hsl("</span></span><span class="pln"> </span><span class="pun">+</span><span class="pln"> hslComponents</span><span class="pun">[</span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="hljs-string"><span class="str">", "</span></span><span class="pln"> </span><span class="pun">+</span><span class="pln"> hslComponents</span><span class="pun">[</span><span class="hljs-number"><span class="lit">1</span></span><span class="pun">]</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="hljs-string"><span class="str">"%, "</span></span><span class="pln"> </span><span class="pun">+</span><span class="pln">  newLum </span><span class="pun">+</span><span class="pln"> </span><span class="hljs-string"><span class="str">"%)"</span></span><span class="hljs-comment"><span class="pun">;</span></span><span class="pln">
        arizona</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">style</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">background</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">"hsl(48, "</span></span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="hljs-number"><span class="lit">100</span></span><span class="pln"> </span><span class="pun">*</span><span class="pln"> vertRoll </span><span class="pun">+</span><span class="pln"> </span><span class="hljs-string"><span class="str">"%, "</span></span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="hljs-number"><span class="lit">88</span></span><span class="pln"> </span><span class="pun">*</span><span class="pln"> vertRoll </span><span class="pun">+</span><span class="pln"> </span><span class="hljs-string"><span class="str">"%)"</span></span><span class="hljs-comment"><span class="pun">;</span></span><span class="pln">
        sun</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">style</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">transform</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">"translate3d(0,"</span></span><span class="pln"> </span><span class="pun">+</span><span class="pln"> window</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">scrollY</span></span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="hljs-number"><span class="lit">10</span></span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="hljs-string"><span class="str">"px, 0)"</span></span><span class="hljs-comment"><span class="pun">;</span></span><span class="pln">
    </span><span class="pun">})</span><span class="pln">
</span><span class="pun">}</span></code></pre>

<p>
	هذه الدالة تفعل ما يلي بالترتيب:
</p>

<ol>
<li>
		الحصول على الخاصية <code>fill</code> لكل عنصر <code>path</code>
	</li>
	<li>
		تحديد مدى تمرير النافذة
	</li>
	<li>
		استخلاص قيمة HSL من كل عنصر <code>path</code>
	</li>
	<li>
		تعديل سطوع العنصر اعتمادًا على مقدار التمرير
	</li>
	<li>
		إعادة تجميع لون HSL لكل عنصر <code>path</code> الذي يضم السطوع الجديد، وتطبيقه على كل عنصر
	</li>
	<li>
		تعديل خاصية <code>background</code> لعنصر SVG، وأيضًا اعتمادًا على مقدار التمرير
	</li>
	<li>
		تمرير عنصر <code>sun</code> إلى الأسفل باستخدام <code>translate3d</code> لإنشاء تأثير الغروب
	</li>
</ol>
<p>
	ملاحظة: لا تعمل ميزة CSS transforms على عناصر SVG في متصفح Internet Explorer أو Edge بعد، على الرغم من أنَّ مفترض أن تدعم الإصدارات القادمة تلك الميزة.<br>
	تُستدعى الدالة باستخدام <code>requestAnimationFrame</code> لتحسين الأداء:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7416_11" style="">
<code class="hljs javascript"><span class="pln">window</span><span class="pun">.</span><span class="pln">onscroll </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">function</span></span><span class="hljs-params"><span class="pun">()</span></span><span class="pln"> </span><span class="pun">{</span></span><span class="pln">
    window</span><span class="pun">.</span><span class="pln">requestAnimationFrame</span><span class="pun">(</span><span class="pln">scrollHandler</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></code></pre>

<h3 id="تبطيء-التأثير">
	تبطيء التأثير
</h3>

<p>
	قد تواجه إشكاليات عند ربط العناصر بالتمرير، فقد تتحول العناصر بسرعة كبيرة مما يجعلك تفقد شعورك بالتأثير… لذا فإنَّ أسهل طريقة لتبطيء التأثير هي استخدام مقياس للتمرير. غيّر الشيفرة السابقة لتصبح كما يلي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7416_11" style="">
<code class="hljs javascript"><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> </span><span class="pun">(</span><span class="pln">window</span><span class="pun">.</span><span class="pln">scrollY </span><span class="pun">&lt;</span><span class="pln"> </span><span class="typ">SVGoffsettop</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="hljs-number"><span class="lit">4</span></span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
      </span><span class="hljs-built_in"><span class="typ">Array</span></span><span class="pun">.</span><span class="pln">prototype</span><span class="pun">.</span><span class="pln">forEach</span><span class="pun">.</span><span class="pln">call</span><span class="pun">(</span><span class="pln">mesaLayers</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">function</span></span><span class="hljs-params"><span class="pun">(</span><span class="pln">layer</span><span class="pun">)</span></span><span class="pln"> </span><span class="pun">{</span></span><span class="pln"> 
          </span><span class="hljs-keyword"><span class="kwd">var</span></span><span class="pln"> layerFill </span><span class="pun">=</span><span class="pln"> layer</span><span class="pun">.</span><span class="pln">getAttribute</span><span class="pun">(</span><span class="hljs-string"><span class="str">"fill"</span></span><span class="pun">),</span><span class="pln">
          vertRoll </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-built_in"><span class="typ">Math</span></span><span class="pun">.</span><span class="pln">abs</span><span class="pun">((</span><span class="pln">window</span><span class="pun">.</span><span class="pln">scrollY </span><span class="pun">/</span><span class="pln"> </span><span class="hljs-number"><span class="lit">4</span></span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="typ">SVGoffsettop</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="typ">SVGoffsettop</span><span class="pun">;</span><span class="pln">
</span><span class="pun">…</span></code></pre>

<h3 id="الخلاصة-وأمور-يمكن-تحسينها">
	الخلاصة وأمور يمكن تحسينها
</h3>

<p>
	عادةً يُستعمَل هذا التأثير بعد ضبط الخاصية <code>position: fixed</code> على عنصر SVG لإبقائه ظاهرًا أثناء تمرير الصفحة، إلا أنني لم أفعل ذلك هنا لأغراضٍ توضيحية. يمكن أيضًا دمج تأثير parallax معه عند التمرير، لكنني قررتُ أن أركِّز على تأثير غروب الشمس فقط.<br>
	هنالك جانبان يمكن تطويرهما في السكربت:
</p>

<ol>
<li>
		تكرار استخراج قيم ألوان HSL وتركيبها، فمن الأفضل جعل تلك القيم كخاصيات لكل عنصر لكي يتم الوصول إليها بسهولة عبر السكربت، بدلًا من إعادة حسابها كل مرة.
	</li>
	<li>
		ألوان خلفية السماء مكتوبة ضمن السكربت؛ ومن الأفضل إسناد الألوان باستخدام CSS، مما يجعل السكربت قادرًا على التعامل مع التغييرات في العرض دون الحاجة إلى تكرار التغييرات.
	</li>
</ol>
<h2 id="إظهار-فيديو-في-الخلفية">
	إظهار فيديو في الخلفية
</h2>

<p style="text-align: center;">
	<img alt="3-LayeredScrollingVideowithBlendModes.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="22957" data-unique="1xjyw2a92" src="https://academy.hsoub.com/uploads/monthly_2017_04/3-LayeredScrollingVideowithBlendModes.jpg.84a8cd6e3dcb9a7a1af3423638e24bd3.jpg"></p>

<p>
	(<a href="https://codepen.io/dudleystorey/pen/WQrPRY" rel="external nofollow">تجربة حية</a>)<br>
	نُشِرَت مقالة عن <a href="http://thenewcode.com/777/Create-Fullscreen-HTML5-Page-Background-Video" rel="external nofollow">كيفية إنشاء فيديو في كامل خلفية الصفحة باستخدام HTML5</a> ، لكن أتت أسئلة على ذاك المقال للسؤال عن كيفية إنشاء فيديو يظهر خلف المحتوى، لكن يمكن تمريره كباقي محتويات الصفحة.<br>
	فاجأني ذلك قليلًا، لأنَّ بالإمكان فعل ذلك باستخدام CSS مع نفس التقنيات التي نستعملها مع الصور… لكن أتتني الفرصة هنا لإعطاء مثال عن أنماط الاندماج (blend modes).
</p>

<h3 id="الشيفرات">
	الشيفرات
</h3>

<p>
	تبدو شيفرة إضافة مقطع الفيديو تقليديةً، حيث سنضعها داخل وسم <code>&lt;main&gt;</code> (بدلًا من وضعها مباشرةً بعد العنصر <code>&lt;body&gt;</code> كما في المقالة الأصلية)، وسأفترض في هذا المثال أنَّ وسم <code>video</code> موجودٌ داخل العنصر <code>&lt;header&gt;</code> ضمن وسم <code>&lt;main&gt;</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7416_11" style="">
<code class="hljs xml"><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">main</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">header</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">video</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">autoplay</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">loop</span></span><span class="tag">&gt;</span></span><span class="pln">
      </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">source</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">src</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"forest-fire.webm"</span></span><span class="tag">&gt;</span></span><span class="pln">
      </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">source</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">src</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"forest-fire.mp4"</span></span><span class="tag">&gt;</span></span><span class="pln">
    </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">video</span></span><span class="tag">&gt;</span></span><span class="pln">
  </span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">header</span></span><span class="tag">&gt;</span></span></code></pre>

<p>
	ملاحظة: يجب أن يتبع الفيديو نفس القواعد العامة لمقاطع الفيديو التي تعمل في الخلفية الموجودة في<a href="http://thenewcode.com/777/Create-Fullscreen-HTML5-Page-Background-Video#considerations" rel="external nofollow"> المقالة الأصلية</a>.<br>
	يجب تنسيق الفيديو بأنماط CSS مماثلة لتلك التي كنتَ ستستعملها لعرض الصور المتجاوبة بكامل العرض:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7416_11" style="">
<code class="hljs css"><span class="hljs-tag"><span class="pln">main</span></span><span class="pln"> </span><span class="hljs-rules"><span class="pun">{</span><span class="pln"> 
  </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">width</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">80</span></span><span class="pun">%</span></span></span><span class="pun">;</span><span class="pln">
  </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">max</span><span class="pun">-</span><span class="pln">width</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">750</span></span><span class="lit">px</span></span></span><span class="pun">;</span><span class="pln">
  </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">margin</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">0</span></span><span class="pln"> </span><span class="kwd">auto</span></span></span><span class="pun">;</span><span class="pln">
</span><span class="hljs-rule"><span class="pun">}</span></span></span><span class="pln">
</span><span class="hljs-tag"><span class="pln">main</span></span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="hljs-tag"><span class="pln">header</span></span><span class="pln"> </span><span class="hljs-tag"><span class="pln">video</span></span><span class="pln"> </span><span class="hljs-rules"><span class="pun">{</span><span class="pln">
  </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">width</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">100</span></span><span class="pun">%</span></span></span><span class="pun">;</span><span class="pln">
  </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">height</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="kwd">auto</span></span></span><span class="pun">;</span><span class="pln">
</span><span class="hljs-rule"><span class="pun">}</span></span></span></code></pre>

<p>
	ملاحظة: إذا أردتَ أن يظهر الفيديو بكامل عرض الشاشة، فبدِّل قيمة الخاصيتين <code>width</code> و <code>max-width</code> للعنصر <code>main</code> لتوسعته.<br>
	يجب إضافة «طبقة» أمام مقطع الفيديو فيها ترويسة ورابط للانتقال إلى محتوى الصفحة. العناصر التالية يجب أن توضع بعد الوسم <code>&lt;video&gt;</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7416_11" style="">
<code class="hljs xml"><span class="pln">   </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">h1</span></span><span class="tag">&gt;</span></span><span class="pln">A world Aflame</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">h1</span></span><span class="tag">&gt;</span></span><span class="pln">
   </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">a</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">href</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"#maincontent"</span></span><span class="tag">&gt;</span></span><span class="pln">▼</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">a</span></span><span class="tag">&gt;</span></span><span class="pln">
</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">header</span></span><span class="tag">&gt;</span></span></code></pre>

<p>
	سيؤدي الضغط على الرابط إلى الانتقال إلى العنصر ذي المعرِّف <code>maincontent</code>. يجب أن نُعدِّل CSS الآن للسماح بإظهار العناصر الجديدة كطبقة تعلو مقطع الفيديو:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7416_11" style="">
<code class="hljs css"><span class="hljs-tag"><span class="pln">main</span></span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="hljs-tag"><span class="pln">header</span></span><span class="pln"> </span><span class="hljs-rules"><span class="pun">{</span><span class="pln"> 
  </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">position</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> relative</span></span></span><span class="pun">;</span><span class="pln">
</span><span class="hljs-rule"><span class="pun">}</span></span></span></code></pre>

<p>
	أنماط CSS للترويسة <code>&lt;h1&gt;</code> وللرابط:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7416_11" style="">
<code class="hljs css"><span class="hljs-tag"><span class="pln">main</span></span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="hljs-tag"><span class="pln">header</span></span><span class="pln"> </span><span class="hljs-tag"><span class="pln">h1</span></span><span class="pln"> </span><span class="hljs-rules"><span class="pun">{</span><span class="pln">
  </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">position</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> absolute</span></span></span><span class="pun">;</span><span class="pln">
  </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">bottom</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">40</span></span><span class="pun">%</span></span></span><span class="pun">;</span><span class="pln">
  </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">left</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">1</span></span><span class="lit">rem</span></span></span><span class="pun">;</span><span class="pln">
  </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">font</span><span class="pun">-</span><span class="pln">size</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">4</span></span><span class="lit">rem</span></span></span><span class="pun">;</span><span class="pln">
  </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">text</span><span class="pun">-</span><span class="pln">transform</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> uppercase</span></span></span><span class="pun">;</span><span class="pln">
  </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">mix</span><span class="pun">-</span><span class="pln">blend</span><span class="pun">-</span><span class="pln">mode</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> overlay</span></span></span><span class="pun">;</span><span class="pln">
</span><span class="hljs-rule"><span class="pun">}</span></span></span><span class="pln">
</span><span class="hljs-tag"><span class="pln">main</span></span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="hljs-tag"><span class="pln">header</span></span><span class="pln"> </span><span class="hljs-tag"><span class="pln">a</span></span><span class="pln"> </span><span class="hljs-rules"><span class="pun">{</span><span class="pln">
  </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">display</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> block</span></span></span><span class="pun">;</span><span class="pln">
  </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">text</span><span class="pun">-</span><span class="pln">decoration</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> none</span></span></span><span class="pun">;</span><span class="pln">
  </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">font</span><span class="pun">-</span><span class="pln">size</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">2</span></span><span class="lit">rem</span></span></span><span class="pun">;</span><span class="pln">
  </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">color</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-hexcolor"><span class="com">#fff</span></span></span></span><span class="com">;</span><span class="pln">
  </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">opacity</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="pun">.</span><span class="hljs-number"><span class="lit">5</span></span></span></span><span class="pun">;</span><span class="pln">
  </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">position</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> absolute</span></span></span><span class="pun">;</span><span class="pln">
  </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">bottom</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">1.5</span></span><span class="lit">rem</span></span></span><span class="pun">;</span><span class="pln">
  </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">width</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">100</span></span><span class="pun">%</span></span></span><span class="pun">;</span><span class="pln">
  </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">text</span><span class="pun">-</span><span class="pln">align</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> center</span></span></span><span class="pun">;</span><span class="pln">
  </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">transition</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="pun">.</span><span class="hljs-number"><span class="lit">3</span></span><span class="lit">s</span></span></span><span class="pun">;</span><span class="pln">
  </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">animation</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> downwardprompt </span><span class="hljs-number"><span class="lit">2</span></span><span class="lit">s</span><span class="pln"> </span><span class="hljs-number"><span class="lit">1</span></span><span class="lit">s</span></span></span><span class="pun">;</span><span class="pln">
</span><span class="hljs-rule"><span class="pun">}</span></span></span><span class="pln">
</span><span class="hljs-tag"><span class="pln">main</span></span><span class="pln"> </span><span class="pun">&gt;</span><span class="pln"> </span><span class="hljs-tag"><span class="pln">header</span></span><span class="pln"> </span><span class="hljs-tag"><span class="pln">a</span></span><span class="hljs-pseudo"><span class="pun">:</span><span class="pln">hover</span></span><span class="pln"> </span><span class="hljs-rules"><span class="pun">{</span><span class="pln">
  </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">opacity</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">1</span></span></span></span><span class="pun">;</span><span class="pln">
</span><span class="hljs-rule"><span class="pun">}</span></span></span></code></pre>

<p>
	سيتم تطبيق تأثير حركي على السهم بعد عدِّة ثواني من تحميل الصفحة، مما يلفت انتباه المستخدم إليه:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7416_11" style="">
<code class="hljs css"><span class="hljs-at_rule"><span class="lit">@</span><span class="hljs-keyword"><span class="lit">keyframes</span></span><span class="pln"> downwardprompt </span></span><span class="pun">{</span><span class="pln">
  </span><span class="hljs-tag"><span class="pln">to</span></span><span class="pln"> </span><span class="hljs-rules"><span class="pun">{</span><span class="pln"> 
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">transform</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-function"><span class="pln">translateY</span><span class="pun">(</span><span class="hljs-number"><span class="lit">2</span></span><span class="lit">rem</span><span class="pun">)</span></span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">opacity</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">0</span></span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="pun">}</span></span></span><span class="pln">
</span><span class="pun">}</span></code></pre>

<p>
	هذا كل ما في الأمر، بالطبع يمكنك القيام بالكثير باستخدام هذه التقنية، إلا أنَّ شيفرات CSS الأساسية ستبقى نفسها تقريبًا.
</p>

<h2 id="صور-متحركة-بتأثير-parallax-باستخدام-css-3d-و-javascript">
	صور متحركة بتأثير parallax باستخدام CSS 3D و JavaScript
</h2>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="22958" href="https://academy.hsoub.com/uploads/monthly_2017_04/4-ParallaxImageScrollingAnimationCSS3D.jpg.e0521b4e19d4e8eb7b7da3d61290e419.jpg" rel=""><img alt="4-ParallaxImageScrollingAnimationCSS3D.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="22958" data-unique="to6327b7n" src="https://academy.hsoub.com/uploads/monthly_2017_04/4-ParallaxImageScrollingAnimationCSS3D.thumb.jpg.e0790a60bb22d4fbc0d0395dddf823b4.jpg"></a>
</p>

<p>
	(<a href="https://codepen.io/dudleystorey/pen/YWgAEP" rel="external nofollow">تجربة حية</a>)<br>
	صحيحٌ أنَّ هنالك الكثير من الطرائق والتقنيات الموجودة على الويب لإنشاء تأثير parallax، لكنني أرى أنَّها تُزِّيف تأثير العمق في الصور، لكنني وجدتُ أنَّ تقنيةCSS 3D تسمح بتغيير مكان الصور على المحور z، مما يجعل تأثير تغيير المنظور حقيقيًا أثناء تحريك الصور إلى الأعلى وإلى الأسفل. وصحيحٌ أنَّ شيفرة هذا المثال ما تزال بدائيةً وبسيطةً، إلا أنَّني أرى أنها تستحق المشاركة.
</p>

<h3 id="الشيفرات-الأساسية">
	الشيفرات الأساسية
</h3>

<p>
	هنالك شيفرة HTML بسيطة جدًا في هذا المثال، وهي عبارة عن عنصر <code>&lt;div&gt;</code> بسيط:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7416_11" style="">
<code class="hljs applescript"><span class="tag">&lt;</span><span class="hljs-keyword"><span class="tag">div</span></span><span class="pln"> </span><span class="hljs-property"><span class="atn">id</span></span><span class="pun">=</span><span class="hljs-string"><span class="atv">"parallax-container"</span></span><span class="tag">&gt;</span><span class="pln">
</span><span class="tag">&lt;/</span><span class="hljs-keyword"><span class="tag">div</span></span><span class="tag">&gt;</span></code></pre>

<p>
	سيُملأ هذا العنصر بالصور المُحمَّلة عبر شيفرة JavaScript، لكن علينا أولًا أن نضبط الأنماط اللازمة لعنصر <code>&lt;div&gt;</code> وللصور التي ستظهر داخله:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7416_11" style="">
<code class="hljs css"><span class="hljs-id"><span class="com">#parallax-container</span></span><span class="com"> </span><span class="hljs-rules"><span class="com">{</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">background</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-hexcolor"><span class="com">#16161d</span></span></span></span><span class="com">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">margin</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">0</span></span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">overflow</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> hidden</span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">perspective</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">1200</span></span><span class="lit">px</span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">height</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">100</span></span><span class="lit">vh</span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">width</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">100</span></span><span class="lit">vw</span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">transform</span><span class="pun">-</span><span class="pln">style</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> preserve</span><span class="pun">-</span><span class="hljs-number"><span class="lit">3</span></span><span class="lit">d</span></span></span><span class="pun">;</span><span class="pln">
</span><span class="hljs-rule"><span class="pun">}</span></span></span><span class="pln">
</span><span class="hljs-id"><span class="com">#parallax-container</span></span><span class="com"> </span><span class="hljs-tag"><span class="com">img</span></span><span class="com"> </span><span class="hljs-rules"><span class="com">{</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">transform</span><span class="pun">-</span><span class="pln">origin</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> center</span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">box</span><span class="pun">-</span><span class="pln">shadow</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">0</span></span><span class="pln"> </span><span class="hljs-number"><span class="lit">0</span></span><span class="pln"> </span><span class="hljs-number"><span class="lit">12</span></span><span class="lit">px</span><span class="pln"> </span><span class="hljs-number"><span class="lit">12</span></span><span class="lit">px</span><span class="pln"> </span><span class="hljs-function"><span class="pln">rgba</span><span class="pun">(</span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">0.4</span></span><span class="pun">)</span></span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">position</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> relative</span></span></span><span class="pun">;</span><span class="pln">
</span><span class="hljs-rule"><span class="pun">}</span></span></span></code></pre>

<p>
	ملاحظة: إن لم تكن تألف التعامل مع <a href="http://thenewcode.com/660/Using-vw-and-vh-Measurements-In-Modern-Site-Design" rel="external nofollow">واحدات vw و vh</a> أو <a href="http://thenewcode.com/826/Web-Developer-Reading-List-CSS-3D" rel="external nofollow">CSS 3D</a>، فاقرأ المزيد عنها في هذه<a href="http://thenewcode.com/reading-lists" rel="external nofollow"> السلاسل</a>.
</p>

<h3 id="الصور-المتحركة">
	الصور المتحركة
</h3>

<p>
	الخطوة التالية هي إضافة الصور، وتنسيقها باستخدام CSS، ثم جعل JavaScript تخفيها ثم تُجري عمليات عليها لتحقيق التأثير المطلوب. ولأنَّ أسماء ملفات الصور لها نفس النمط في هذا المثال (أي <code>wave1.jpg</code> و <code>wave2.jpg</code> …إلخ.) فيمكنني استخدام JavaScript لتوليد أسماء الملفات مع إنشاء بعض المتغيرات التي ستلزمنا لاحقًا في السكربت:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7416_11" style="">
<code class="hljs coffeescript"><span class="hljs-reserved"><span class="kwd">var</span></span><span class="pln"> container </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">document</span></span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="hljs-string"><span class="str">"parallax-container"</span></span><span class="pun">),</span><span class="pln">
waveSrc </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[],</span><span class="pln">
waves </span><span class="pun">=</span><span class="pln"> </span><span class="pun">[],</span><span class="pln">
imgLoc </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">""</span></span><span class="pun">,</span><span class="pln">
j </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">;</span><span class="pln">

</span><span class="hljs-keyword"><span class="kwd">for</span></span><span class="pln"> </span><span class="pun">(</span><span class="hljs-reserved"><span class="kwd">var</span></span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-number"><span class="lit">10</span></span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    waveSrc</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> imgLoc</span><span class="pun">+</span><span class="hljs-string"><span class="str">"wave"</span></span><span class="pun">+(</span><span class="pln">i</span><span class="pun">+</span><span class="hljs-number"><span class="lit">1</span></span><span class="pun">)+</span><span class="hljs-string"><span class="str">".jpg"</span></span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></code></pre>

<p>
	سنحتاج أيضًا إلى بعض الأرقام العشوائية، لذا سأولدها باستخدام هذه الدالة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7416_11" style="">
<code class="hljs rsl"><span class="kwd">function</span><span class="pln"> getRandomInRange</span><span class="pun">(</span><span class="hljs-built_in"><span class="pln">min</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">max</span></span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">return</span></span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="hljs-built_in"><span class="pln">floor</span></span><span class="pun">(</span><span class="typ">Math</span><span class="pun">.</span><span class="hljs-built_in"><span class="pln">random</span></span><span class="pun">()</span><span class="pln"> </span><span class="pun">*</span><span class="pln"> </span><span class="pun">(</span><span class="hljs-built_in"><span class="pln">max</span></span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">min</span></span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="hljs-number"><span class="lit">1</span></span><span class="pun">))</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">min</span></span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></code></pre>

<p>
	سنحتاج أيضًا إلى مرجع (reference) إلى الصور التي جرى تحميلها، بالإضافة إلى عرض وارتفاع الشاشة الحالي (بافتراض أنَّ نافذة المتصفح مُكبَّرَة).
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7416_11" style="">
<code class="hljs avrasm"><span class="kwd">var</span><span class="pln"> screenWidth </span><span class="pun">=</span><span class="pln"> window</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">screen</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">width</span></span><span class="pun">,</span><span class="pln">
screenHeight </span><span class="pun">=</span><span class="pln"> window</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">screen</span></span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">height</span></span><span class="hljs-comment"><span class="pun">;</span></span></code></pre>

<p>
	وعند اكتمال تحميل الصور وإضافتها إلى عنصر <code>&lt;div&gt;</code>، فسنوفِّر لها خاصيات –وهي <code>‎.xPlane</code> و <code>‎.yPlane</code> و <code>‎.zPlane</code>– بقيمٍ عشوائية، والتي ستُحدِّد موضع الصورة في فضاءٍ ثلاثي الأبعاد. سأترك قيم الخاصية <code>alt</code> في هذا المثال فارغةً وذلك للاختصار:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7416_11" style="">
<code class="hljs javascript"><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">function</span></span><span class="pln"> </span><span class="hljs-title"><span class="pln">preloadImage</span></span><span class="hljs-params"><span class="pun">(</span><span class="pln">filename</span><span class="pun">)</span></span><span class="pun">{</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">var</span></span><span class="pln"> img</span><span class="pun">=</span><span class="hljs-keyword"><span class="kwd">new</span></span><span class="pln"> </span><span class="typ">Image</span><span class="pun">();</span><span class="pln">
    img</span><span class="pun">.</span><span class="pln">onload </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">function</span></span><span class="hljs-params"><span class="pun">()</span></span><span class="pun">{</span></span><span class="pln"> 
        img</span><span class="pun">.</span><span class="pln">xPlane </span><span class="pun">=</span><span class="pln"> getRandomInRange</span><span class="pun">(-</span><span class="hljs-number"><span class="lit">500</span></span><span class="pun">,</span><span class="pln"> screenWidth </span><span class="pun">-</span><span class="pln"> </span><span class="hljs-number"><span class="lit">500</span></span><span class="pun">);</span><span class="pln">
        img</span><span class="pun">.</span><span class="pln">yPlane </span><span class="pun">=</span><span class="pln"> getRandomInRange</span><span class="pun">(</span><span class="hljs-number"><span class="lit">500</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-number"><span class="lit">1000</span></span><span class="pun">);</span><span class="pln">
        img</span><span class="pun">.</span><span class="pln">zPlane </span><span class="pun">=</span><span class="pln"> getRandomInRange</span><span class="pun">(</span><span class="hljs-number"><span class="lit">300</span></span><span class="pun">,</span><span class="hljs-number"><span class="lit">2000</span></span><span class="pun">);</span><span class="pln">
        img</span><span class="pun">.</span><span class="pln">style </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">"transform: translate3d("</span></span><span class="pln"> </span><span class="pun">+</span><span class="pln"> img</span><span class="pun">.</span><span class="pln">xPlane </span><span class="pun">+</span><span class="hljs-string"><span class="str">"px, "</span></span><span class="pln"> </span><span class="pun">+</span><span class="pln"> 
            img</span><span class="pun">.</span><span class="pln">yPlane </span><span class="pun">+</span><span class="pln"> </span><span class="hljs-string"><span class="str">"px, -"</span></span><span class="pln"> </span><span class="pun">+</span><span class="pln"> img</span><span class="pun">.</span><span class="pln">zPlane </span><span class="pun">+</span><span class="hljs-string"><span class="str">"px)"</span></span><span class="pun">;</span><span class="pln">
       container</span><span class="pun">.</span><span class="pln">appendChild</span><span class="pun">(</span><span class="pln">img</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
    imgLoc </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">""</span></span><span class="pun">;</span><span class="pln">
    img</span><span class="pun">.</span><span class="pln">src</span><span class="pun">=</span><span class="pln"> imgLoc </span><span class="pun">+</span><span class="pln"> filename</span><span class="pun">;</span><span class="pln">
    img</span><span class="pun">.</span><span class="pln">alt </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">""</span></span><span class="pun">;</span><span class="pln">
    waves</span><span class="pun">[</span><span class="pln">j</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> img</span><span class="pun">;</span><span class="pln">
    j</span><span class="pun">++;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">

</span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">function</span></span><span class="pln"> </span><span class="hljs-title"><span class="pln">loadImages</span></span><span class="hljs-params"><span class="pun">()</span></span><span class="pun">{</span></span><span class="pln">
    </span><span class="hljs-keyword"><span class="kwd">for</span></span><span class="pln"> </span><span class="pun">(</span><span class="hljs-keyword"><span class="kwd">var</span></span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> waveSrc</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln"> </span><span class="pun">++</span><span class="pln">i</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="hljs-keyword"><span class="kwd">var</span></span><span class="pln"> filename </span><span class="pun">=</span><span class="pln"> waveSrc</span><span class="pun">[</span><span class="pln">i</span><span class="pun">];</span><span class="pln">
        preloadImage</span><span class="pun">(</span><span class="pln">filename</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></code></pre>

<p>
	أخيرًا، ستُحرَّك الصور باستخدام دالة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7416_11" style="">
<code class="hljs php"><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">function</span></span><span class="pln"> </span><span class="hljs-title"><span class="pln">moveImages</span></span><span class="hljs-params"><span class="pun">()</span></span><span class="pun">{</span></span><span class="pln">
    waves</span><span class="pun">.</span><span class="hljs-keyword"><span class="pln">forEach</span></span><span class="pun">(</span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">function</span></span><span class="hljs-params"><span class="pun">(</span><span class="pln">image</span><span class="pun">)</span></span><span class="pln"> </span><span class="pun">{</span></span><span class="pln">
            image</span><span class="pun">.</span><span class="pln">yPlane </span><span class="pun">=</span><span class="pln"> image</span><span class="pun">.</span><span class="pln">yPlane </span><span class="pun">-</span><span class="pln"> </span><span class="hljs-number"><span class="lit">2</span></span><span class="pun">;</span><span class="pln">
            image</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">cssText </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-string"><span class="str">"transform: translate3d("</span></span><span class="pln"> </span><span class="pun">+</span><span class="pln"> image</span><span class="pun">.</span><span class="pln">xPlane</span><span class="pun">+</span><span class="hljs-string"><span class="str">"px, 
"</span></span><span class="pln"> </span><span class="pun">+</span><span class="pln"> image</span><span class="pun">.</span><span class="pln">yPlane</span><span class="pun">+</span><span class="hljs-string"><span class="str">"px,  -"</span></span><span class="pln"> </span><span class="pun">+</span><span class="pln"> image</span><span class="pun">.</span><span class="pln">zPlane </span><span class="pun">+</span><span class="pln"> </span><span class="hljs-string"><span class="str">"px); z-index: "</span></span><span class="pln"> </span><span class="pun">+</span><span class="pln"> image</span><span class="pun">.</span><span class="pln">zIndex</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">});</span><span class="pln">
    window</span><span class="pun">.</span><span class="pln">requestAnimationFrame</span><span class="pun">(</span><span class="pln">moveImages</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></code></pre>

<p>
	وسيتم تشغيل المثال باستدعاء الدوال المناسبة في نهاية السكربت:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_7416_11" style="">
<code class="hljs javascript"><span class="pln">loadImages</span><span class="pun">();</span><span class="pln">
window</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="hljs-string"><span class="str">"load"</span></span><span class="pun">,</span><span class="pln"> 
    </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">function</span></span><span class="hljs-params"><span class="pun">()</span></span><span class="pln"> </span><span class="pun">{</span></span><span class="pln"> 
        window</span><span class="pun">.</span><span class="pln">requestAnimationFrame</span><span class="pun">(</span><span class="pln">moveImages</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">});</span></code></pre>

<h3 id="تحسينات-إضافية-على-المثال">
	تحسينات إضافية على المثال
</h3>

<p>
	ما يزال هذا المثال مبدئيًا، وهنالك عدِّة أشياء يمكن إجراؤها لتطويره:<br>
	1. سيستمر تشغيل السكربت حتى بعد أن تختفي الصور من أعلى العنصر الحاوي لها، وستستمر بالحركة إلى اللانهاية؛ لذا من الأفضل أنَّ نُزيل الصور من بداية المصفوفة بعد اختفائها ثم إضافتها مرةً أخرى لتظهر مجددًا.<br>
	2. ربما من الأفضل أنَّ نُقلِّل من العشوائية في مواضع الصور، فالآن يمكن أن تظهر إحدى الصور خلف صورةٍ أخرى مباشرةً، أو قريبة منها كثيرًا في البُعد z (وبالتالي ستتحرك الصورتان بسرعةٍ قريبةٍ من بعضهما). ولفعل ذلك علينا أن نقارن أماكن الصور الجديدة بتلك التي أنشأناها من قبل في المصفوفة، وتوليد قيمة جديدة إن كانت القيمتان متقاربتين.<br>
	3. سيتم تحريك الصور تلقائيًا، إذا أردتَ أن تربط حركة الصور بتغيير شريط التمرير في الصفحة، فعليك أن تُغيّر موضع الصور بالنسبة إلى <code>window.scrollY</code>.
</p>

<p>
	ترجمة وبتصرّف للمقالات <a href="http://thenewcode.com/918/A-Custom-Scrolling-Element-With-Keyboard-Accessibility" rel="external nofollow">A Custom Scrolling Element With Keyboard Accessibility</a> و <a href="http://thenewcode.com/16/Scrolling-Background-Video-with-Layered-Content" rel="external nofollow">Scrolling Background Video with Layered Content</a> و <a href="http://thenewcode.com/1098/A-Scrolling-SVG-Sunset" rel="external nofollow">A Scrolling SVG Sunset</a> و <a href="http://thenewcode.com/1123/Parallax-Image-Scrolling-Animation-with-CSS-3D-and-JavaScript" rel="external nofollow">Parallax Image Scrolling Animation with CSS 3D and JavaScript</a> لصاحبها Dudley Storey
</p>
]]></description><guid isPermaLink="false">475</guid><pubDate>Tue, 06 Dec 2016 21:00:00 +0000</pubDate></item><item><title>&#x62A;&#x623;&#x62B;&#x64A;&#x631;&#x627;&#x62A; &#x627;&#x644;&#x62A;&#x645;&#x631;&#x64A;&#x631; &#x641;&#x64A; &#x635;&#x641;&#x62D;&#x627;&#x62A; &#x627;&#x644;&#x648;&#x64A;&#x628; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; Javascript &#x648;CSS&#x2013; &#x627;&#x644;&#x62C;&#x632;&#x621; &#x627;&#x644;&#x62B;&#x627;&#x646;&#x64A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%AA%D8%A3%D8%AB%D9%8A%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D9%85%D8%B1%D9%8A%D8%B1-%D9%81%D9%8A-%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-javascript-%D9%88css%E2%80%93-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%AB%D8%A7%D9%86%D9%8A-r474/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_04/22.jpg.a2d1a22d65fe10eb467115c9ba58010e.jpg" /></p>

<p id="تأثيرات-التمرير-في-صفحات-الويب-باستخدام-javascript-وcss-الجزء-الثاني">
	أهلًا بك في هذه السلسلة التي تتحدث عن تأثيرات التمرير (Scrolling Effects)، سنستعرض في هذه السلسلة عددٌ من تأثيرات التمرير وسنشرح آلية عملها وسنجرِّبها عمليًا.<br>
	يمكننا الاستفادة من الحدث <code>scroll</code> في JavaScript لإجراء تأثيرات عند تمرير صفحة الويب؛ لكن إن فعلنا ذلك دون إتقان فالنتيجة كارثية، أما إذا أحسنا صنعنا فيمكن لتأثيرات التمرير أن تبهر الزوار وتشعرهم أنَّ موقعك مميز.<br>
	تحدثنا في المقالة السابقة عن التأثيرات الآتية:
</p>

<ul>
<li>
		إخفاء صورة خلفية تدريجيًا عند التمرير
	</li>
	<li>
		توضيح الصورة عند التمرير
	</li>
	<li>
		تدوير العناصر عند التمرير
	</li>
	<li>
		تأثير اختلاف المظهر parallax
	</li>
</ul>
<p>
	أما المقالة الحالية (الثانية) فهي تتضمن التأثيرات الآتية:
</p>

<ul>
<li>
		إظهار صورة الخلفية عند التمرير باستخدام CSS فقط
	</li>
	<li>
		تمرير سلس للصفحة
	</li>
	<li>
		تطبيق تأثير عدم الوضوح على المحتوى خلف شريط الانتقال
	</li>
</ul>
<p>
	وسنشرح في آخر مقالة طريقة إنشاء:
</p>

<ul>
<li>
		عنصر قابل للتمرير مع إمكانية وصول مخصصة من لوحة المفاتيح
	</li>
	<li>
		تأثير غروب الشمس باستخدام SVG
	</li>
	<li>
		إظهار فيديو في الخلفية
	</li>
	<li>
		صور متحركة بتأثير parallax باستخدام CSS 3D و JavaScript
	</li>
</ul>
<p>
	سأقدِّم لك في بداية كل قسم رابطًا لتجربة المثال تجربةً حيةً على المتصفح. سيسهل عليك كثيرًا أن تفهم الشرح والشيفرات بعد تجربتك للتأثير.
</p>

<h2 id="إظهار-صورة-الخلفية-عند-التمرير-باستخدام-css-فقط">
	إظهار صورة الخلفية عند التمرير باستخدام CSS فقط
</h2>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="22952" href="https://academy.hsoub.com/uploads/monthly_2017_04/1-EasyFullscreenPageScrollWithBackgroundReveal.jpg.2b657183674a4da213a549b1db9e6f7b.jpg" rel=""><img alt="1-EasyFullscreenPageScrollWithBackgroundReveal.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="22952" data-unique="o3kk9d36c" src="https://academy.hsoub.com/uploads/monthly_2017_04/1-EasyFullscreenPageScrollWithBackgroundReveal.thumb.jpg.735d637d04fe9d76d8524815b6958e1e.jpg"></a>
</p>

<p>
	(<a href="https://codepen.io/dudleystorey/pen/lejFx" rel="external nofollow">تجربة حية</a>)<br>
	طريقة عرض جميلة وشائعة هي «إظهار صورة الخلفية عند التمرير»: فكلما مَرَّرنا إلى الأسفل، فستصبح صورة الخلفية المخفية ظاهرةً للمستخدم.<br>
	صحيحٌ أنَّ طريقة العرض هذه أصبحت شائعة في الآونة الأخيرة، إلا أنَّها جيدة حيث تجعل المحتوى مركَّزًا ومختصرًا إلى بضع صور وفقرات قصيرة من النص.<br>
	يُحقَّق هذا التأثير عادةً باستخدام إطار عمل من إطارات JavaScript مع إحدى الإضافات؛ وهذا غير ضروري أبدًا في المتصفحات الحديثة، وسأريك طريقة فعل ذلك.
</p>

<h3 id="النوافذ-والجدران">
	«النوافذ والجدران»
</h3>

<p>
	الفكرة الأساسية لهذا التأثير هي إنشاء سلسلة من «النوافذ» المفتوحة و«الجدران» المغلقة فوق بعضها بعضًا، وكلٌ منها له نفس الطول والعرض الخاص بإطار العرض (viewport).<br>
	لنبدأ بإنشاء شيفرة HTML بسيطة. يمكن إنشاء «النوافذ» و«الجدران» من أيّ عنصر HTML قادر على احتواء العناصر الأخرى؛ وسنستخدم في هذا المثال وسوم <code>&lt;section&gt;</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6613_9" style="">
<span class="pun">&lt;</span><span class="pln">section</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">Come</span><span class="pln"> </span><span class="typ">To</span><span class="pln"> </span><span class="typ">Iceland</span><span class="pun">&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">section</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;</span><span class="pln">section</span><span class="pun">&gt;</span><span class="pln">
    </span><span class="pun">&lt;</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="typ">The</span><span class="pln"> last settled part of </span><span class="typ">Europe</span><span class="pun">,</span><span class="pln"> much of </span><span class="typ">Iceland</span><span class="pln"> remains pristine and untouched</span><span class="pun">.&lt;/</span><span class="pln">h1</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">&lt;/</span><span class="pln">section</span><span class="pun">&gt;</span><span class="pln">
</span><span class="pun">…</span></pre>

<p>
	لجعل قياس جميع العناصر صحيحًا، فسأحذف أيّة هوامش (<code>margin</code>) من العنصر <code>&lt;body&gt;</code>، تأكد أنَّ العناصر <code>&lt;section&gt;</code> مُقاسة عبر <code>border-box</code>، وتأكد أنَّ لكل عنصرٍ منها له نفس ارتفاع إطار العرض باستخدام واحدات <code>vm</code>. يجب تنسيق النص ليستخدم نفس الواحدات السابقة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6613_9" style="">
<code class="hljs css"><span class="hljs-tag"><span class="pln">body</span></span><span class="pln"> </span><span class="hljs-rules"><span class="pun">{</span><span class="pln"> </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">margin</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">0</span></span></span></span><span class="pun">;</span><span class="pln"> </span><span class="hljs-rule"><span class="pun">}</span></span></span><span class="pln">
</span><span class="hljs-tag"><span class="pln">section</span></span><span class="pln"> </span><span class="hljs-rules"><span class="pun">{</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">box</span><span class="pun">-</span><span class="pln">sizing</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> border</span><span class="pun">-</span><span class="pln">box</span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">height</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">100</span></span><span class="lit">vh</span></span></span><span class="pun">;</span><span class="pln"> 
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">text</span><span class="pun">-</span><span class="pln">align</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> center</span></span></span><span class="pun">;</span><span class="pln"> 
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">padding</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">2</span></span><span class="lit">vw</span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">font</span><span class="pun">-</span><span class="pln">size</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">6</span></span><span class="lit">vw</span></span></span><span class="pun">;</span><span class="pln">
</span><span class="hljs-rule"><span class="pun">}</span></span></span></code></pre>

<p>
	عناصر <code>&lt;section&gt;</code> تأخذ كامل عرض نافذة المتصفح، ولتوسيط محتواها فسنستعمل <a href="https://academy.hsoub.com/programming/css/%D8%AA%D8%B9%D8%B1%D9%81-%D8%B9%D9%84%D9%89-css-flexbox-%D9%88%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A7%D8%B3%D8%AA%D8%B9%D9%85%D8%A7%D9%84%D9%87-%D9%84%D9%87%D9%8A%D9%83%D9%84%D8%A9-%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-r118/" rel="">flexbox</a>، ويجب إجراء المثل على عناصر <code>&lt;section&gt;</code> التي ستعرض صور الخلفية، لذا سأُضمِّن أنماطها أيضًا:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6613_9" style="">
<code class="hljs css"><span class="hljs-tag"><span class="pln">section</span></span><span class="pln"> </span><span class="hljs-rules"><span class="pun">{</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">display</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> flex</span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">align</span><span class="pun">-</span><span class="pln">items</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> center</span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">justify</span><span class="pun">-</span><span class="pln">content</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> center</span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">text</span><span class="pun">-</span><span class="pln">align</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> center</span></span></span><span class="pun">;</span><span class="pln"> 
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">flex</span><span class="pun">-</span><span class="pln">direction</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> column</span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">background</span><span class="pun">-</span><span class="pln">size</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> cover</span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">background</span><span class="pun">-</span><span class="pln">repeat</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="kwd">no</span><span class="pun">-</span><span class="pln">repeat</span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">background</span><span class="pun">-</span><span class="pln">attachment</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="kwd">fixed</span></span></span><span class="pun">;</span><span class="pln">
</span><span class="hljs-rule"><span class="pun">}</span></span></span></code></pre>

<p>
	تُستخدم الخاصية <code>flex-direction</code> لإغلاق أيّة «نوافذ» التي تحتوي عدِّة أسطر نصية. ويجب علينا إضافة نمط خاص بأوّل عنصر <code>&lt;section&gt;</code> لأنَّ النص فيه أكبر، ولونه أبيض، ومكتوبٌ بأحرفٍ كبيرة، مع استخدام الخاصية <a href="https://academy.hsoub.com/programming/css/%D8%A7%D9%84%D8%AF%D9%84%D9%8A%D9%84-%D8%A7%D9%84%D8%B9%D9%85%D9%84%D9%8A-%D9%84%D8%B8%D9%84%D8%A7%D9%84-%D8%A7%D9%84%D8%AE%D8%B7%D9%88%D8%B7-text-shadow-%D9%81%D9%8A-css-r49/" rel="">text-shadow</a> لإضافة ظل لتميزه عن الخلفية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6613_9" style="">
<code class="hljs css"><span class="hljs-tag"><span class="pln">section</span></span><span class="hljs-pseudo"><span class="pun">:</span><span class="pln">first</span><span class="pun">-</span><span class="pln">of</span><span class="pun">-</span><span class="pln">type</span></span><span class="pln"> </span><span class="hljs-rules"><span class="pun">{</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">text</span><span class="pun">-</span><span class="pln">transform</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> uppercase</span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">color</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-hexcolor"><span class="com">#fff</span></span></span></span><span class="com">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">font</span><span class="pun">-</span><span class="pln">size</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">8</span></span><span class="lit">vw</span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">text</span><span class="pun">-</span><span class="pln">shadow</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">0</span></span><span class="pln"> </span><span class="hljs-number"><span class="lit">0</span></span><span class="pln"> </span><span class="hljs-number"><span class="lit">5</span></span><span class="lit">px</span><span class="pln"> </span><span class="hljs-function"><span class="pln">rgba</span><span class="pun">(</span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">,</span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">,</span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">,</span><span class="hljs-number"><span class="lit">0.4</span></span><span class="pun">)</span></span></span></span><span class="pun">;</span><span class="pln">
</span><span class="hljs-rule"><span class="pun">}</span></span></span></code></pre>

<p>
	عناصر <code>&lt;section&gt;</code> الزوجية لها خلفية بيضاء:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6613_9" style="">
<code class="hljs css"><span class="hljs-tag"><span class="pln">section</span></span><span class="hljs-pseudo"><span class="pun">:</span><span class="pln">nth</span><span class="pun">-</span><span class="pln">of</span><span class="pun">-</span><span class="pln">type</span><span class="pun">(</span><span class="pln">even</span><span class="pun">)</span></span><span class="pln"> </span><span class="hljs-rules"><span class="pun">{</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">background</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-hexcolor"><span class="com">#fff</span></span></span></span><span class="com">;</span><span class="pln">
</span><span class="hljs-rule"><span class="pun">}</span></span></span></code></pre>

<p>
	أما عناصر <code>&lt;section&gt;</code> الفردية فلها صور خلفية:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6613_9" style="">
<code class="hljs css"><span class="hljs-tag"><span class="pln">section</span></span><span class="hljs-pseudo"><span class="pun">:</span><span class="pln">nth</span><span class="pun">-</span><span class="pln">of</span><span class="pun">-</span><span class="pln">type</span><span class="pun">(</span><span class="lit">1</span><span class="pun">)</span></span><span class="pln"> </span><span class="hljs-rules"><span class="pun">{</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">background</span><span class="pun">-</span><span class="pln">image</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-function"><span class="pln">url</span><span class="pun">(</span><span class="pln">iceland</span><span class="pun">-</span><span class="pln">fjords</span><span class="pun">.</span><span class="pln">jpg</span><span class="pun">)</span></span></span></span><span class="pun">;</span><span class="pln">
</span><span class="hljs-rule"><span class="pun">}</span></span></span><span class="pln">
</span><span class="hljs-tag"><span class="pln">section</span></span><span class="hljs-pseudo"><span class="pun">:</span><span class="pln">nth</span><span class="pun">-</span><span class="pln">of</span><span class="pun">-</span><span class="pln">type</span><span class="pun">(</span><span class="lit">3</span><span class="pun">)</span></span><span class="pln"> </span><span class="hljs-rules"><span class="pun">{</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">background</span><span class="pun">-</span><span class="pln">image</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-function"><span class="pln">url</span><span class="pun">(</span><span class="pln">iceland</span><span class="pun">-</span><span class="pln">pool</span><span class="pun">-</span><span class="pln">faces</span><span class="pun">.</span><span class="pln">jpg</span><span class="pun">)</span></span></span></span><span class="pun">;</span><span class="pln">
</span><span class="hljs-rule"><span class="pun">}</span></span></span><span class="pln">
</span><span class="hljs-tag"><span class="pln">section</span></span><span class="hljs-pseudo"><span class="pun">:</span><span class="pln">nth</span><span class="pun">-</span><span class="pln">of</span><span class="pun">-</span><span class="pln">type</span><span class="pun">(</span><span class="lit">5</span><span class="pun">)</span></span><span class="pln"> </span><span class="hljs-rules"><span class="pun">{</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">background</span><span class="pun">-</span><span class="pln">image</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-function"><span class="pln">url</span><span class="pun">(</span><span class="pln">iceland</span><span class="pun">-</span><span class="pln">ice</span><span class="pun">.</span><span class="pln">jpg</span><span class="pun">)</span></span></span></span><span class="pun">;</span><span class="pln">
</span><span class="hljs-rule"><span class="pun">}</span></span></span></code></pre>

<p>
	وهذا كل ما في الأمر! صحيحٌ أنَّ المثال السابق يعمل على المتصفحات الحديثة فقط والتي تدعم <code>vh</code> و <code>vm</code> و flexbox؛ وإذا كنتَ تنوي دعم المتصفحات القديمة فعليك استخدام بدائل مثل نمط العرض <code>table-row</code> لكل عنصر <code>&lt;section&gt;</code> …
</p>

<h2 id="تمرير-سلس-للصفحة">
	تمرير سلس للصفحة
</h2>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="22953" href="https://academy.hsoub.com/uploads/monthly_2017_04/2-SmoothPageScrollinPureJavaScript.jpg.4179daf666f04c6a20a33a79cb25003e.jpg" rel=""><img alt="2-SmoothPageScrollinPureJavaScript.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="22953" data-unique="hyqobngqm" src="https://academy.hsoub.com/uploads/monthly_2017_04/2-SmoothPageScrollinPureJavaScript.thumb.jpg.d832bfedc2f45b70ee73dff8a581786f.jpg"></a>
</p>

<p>
	(<a href="https://codepen.io/dudleystorey/pen/pJVVBx" rel="external nofollow">تجربة حية</a>)<br>
	تتواجد في HTML ميزة الانتقال إلى أماكن معيّن في الصفحة، وذلك بتوفير خاصية <code>id</code> للعنصر الذي تريد الانتقال إليه، ومن ثم ربط ذلك عبر عناصر <code>&lt;a&gt;</code>.<br>
	لكن الحركة غير سلسة وستنتقل فوريًا إلى العنصر الهدف؛ ولكن بغرض تحسين طريقة عرض واستخدام الموقع، فيتطلّب أحيانًا تصميم الموقع أن يتم التمرير بشكلٍ سلسٍ أو بطيء إلى نقطةٍ معيّنةٍ في الصفحة.<br>
	قديمًا كانت تُستعمَل jQuery لذلك، لكن من غير المعقول تحميل إطار عمل كامل لاستخدام هذه الميزة فقط؛ وتوفِّر JavaScript طريقةً أفضل وأسرع (من ناحية الأداء) وهي الدالة <code>window.scrollTo</code>.<br>
	سنستخدم عنصر <code>&lt;a&gt;</code> كأساس لهذه التقنية، وبهذه الطريقة سيتم الانتقال إلى الهدف حتى لو لم تعمل شيفرة التمرير السلس لسببٍ من الأسباب.
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6613_9" style="">
<code class="hljs xml"><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">a</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">href</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"#destination"</span></span><span class="tag">&gt;</span></span><span class="pln">Click me: I’m </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">em</span></span><span class="tag">&gt;</span></span><span class="pln">smoooooth</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">em</span></span><span class="tag">&gt;</span></span><span class="pln">.</span><span class="hljs-tag"><span class="tag">&lt;/</span><span class="hljs-title"><span class="tag">a</span></span><span class="tag">&gt;</span></span><span class="pln">
…
 </span><span class="hljs-tag"><span class="tag">&lt;</span><span class="hljs-title"><span class="tag">p</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="atn">id</span></span><span class="pun">=</span><span class="hljs-value"><span class="atv">"destination"</span></span><span class="tag">&gt;</span></span><span class="pln">This is the target, further down the page.</span></code></pre>

<p>
	وكما هو واضح، يجب أن تكون الصفحة طويلةً بعض الشيء وتمتد إلى ما بعد أسفل إطار العرض لكي تعمل هذه التقنية، لأنَّه إذا عُرِضَت كامل محتويات الصفحة في نافذة المتصفح، فلا حاجة إلى التمرير من الأساس؛ ولهذا السبب عليك أن تضع الكثير من المحتوى في الصفحة للتجربة.
</p>

<h3 id="طريقتان-للتمرير-بسلاسة">
	طريقتان للتمرير بسلاسة
</h3>

<p>
	قد يبدو الأمر مربكًا بعض الشيء، إلا أنَّ البنية البرمجية للتمرير السلس موجودة في CSS وفي JavaScript، وأنَّ بعض المتصفحات تدعم تلك البنية البرمجية والأخرى لا تدعمها (انظر فقرة «دعم المتصفحات» في الأسفل).<br>
	ففي CSS إذا أردنا أنَّ يكون التمرير سلسًا لأحد العناصر (وعادةً ما نستخدم العنصر <code>body</code> لكن ذلك ليس ضروريًا) فعلينا أن نضبط الخاصية <code>scroll-behavior</code> ونسند القيمة <code>smooth</code> إليها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6613_9" style="">
<code class="hljs css"><span class="hljs-tag"><span class="pln">body</span></span><span class="pln"> </span><span class="hljs-rules"><span class="pun">{</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">scroll</span><span class="pun">-</span><span class="pln">behavior</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> smooth</span></span></span><span class="pun">;</span><span class="pln">
</span><span class="hljs-rule"><span class="pun">}</span></span></span></code></pre>

<p>
	لاحظ أنَّ كلمة «behavior» (في <code>scroll-behavior</code>) لا تحتوي على حرف «u».
</p>

<h3 id="طريقة-javascript">
	طريقة JavaScript
</h3>

<p>
	سنضيف شيفرة JavaScript إلى نهاية الصفحة لكي تُنفَّذ بعد انتهاء تحميل الصفحة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6613_9" style="">
<code class="hljs avrasm"><span class="kwd">var</span><span class="pln"> anchorLink </span><span class="pun">=</span><span class="pln"> document</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">querySelector</span></span><span class="pun">(</span><span class="hljs-string"><span class="str">"a[href='#destination']"</span></span><span class="pun">),</span><span class="pln">
target </span><span class="pun">=</span><span class="pln"> document</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">getElementById</span></span><span class="pun">(</span><span class="hljs-string"><span class="str">"destination"</span></span><span class="pun">)</span><span class="hljs-comment"><span class="pun">;</span></span><span class="pln">
anchorLink</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">addEventListener</span></span><span class="pun">(</span><span class="hljs-string"><span class="str">"click"</span></span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">e</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">window</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">scrollTo</span></span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        e</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">preventDefault</span></span><span class="pun">()</span><span class="hljs-comment"><span class="pun">;</span></span><span class="pln">
        window</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">scrollTo</span></span><span class="pun">({</span><span class="hljs-string"><span class="str">"behavior"</span></span><span class="pun">:</span><span class="pln"> </span><span class="hljs-string"><span class="str">"smooth"</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-string"><span class="str">"top"</span></span><span class="pun">:</span><span class="pln"> target</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">offsetTop</span></span><span class="pun">})</span><span class="hljs-comment"><span class="pun">;</span></span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">})</span></code></pre>

<p>
	الدالة <code>querySelector</code> تستعمل نفس طريقة كتابة محدِّدات CSS للعثور على أوّل رابط الذي يشير إلى <code>‎#destination</code>؛ والضغط على هذا الرابط سيؤدي إلى تنفيذ عبارة شرطية للتأكد من دعم المتصفح للدالة <code>scrollTo</code>، فإن دعمها المتصفح فستوقف الدالة <code>e.preventDefault</code> المتصفحَ من الانتقال مباشرةً إلى الفقرة الهدف، وسنستخدم الدالة <code>scrollTo</code> بدلًا من ذلك بعد ضبطها ليكون التمرير سلسًا. تأخذ الدالة <code>scrollTo</code> وسيطين هما <code>behavior</code> و top<code>، مع وسيطٍ اختياريٍ هو</code>left<code>، ويقبل آخر وسطين إحداثيات المكان الذي نريد الانتقال إليه.<br>
	يمكن استخدام الدالة</code>window.scroll<code>في المثال السابق، لأنَّ وظيفتها مماثلة لوظيفة الدالة</code>window.scrollTo`.<br>
	مقارنةً مع استخدام إطار عمل، فإنَّ هذه الطريقة أبسط بكثير؛ لكن الجانب السلبي لها هو أنَّها لا تسمح للمصمم بتغيير دالة التوقيت أو حركات التمرير، لتجنّب استعمال المصممين استعمالًا سلبيًا لها.
</p>

<h3 id="إنشاء-سكربت-عام">
	إنشاء سكربت عام
</h3>

<p>
	السكربت السابق يعمل عمله بشكلٍ صحيح، لكنه يتطلب أن تعرف ما هو اسم العنصر الهدف، ولا يمكن تطبيقه إلا على رابطٍ وحيد. ماذا إذا أردت إنشاء سلسلة من الروابط التي تُشير إلى عناصر مختلفة؟ سنحتاج في هذه الحالة إلى جعل السكربت عامًا.<br>
	سنبدأ السكربت بإنشاء دالة التي تسمح لنا بمعالجة كل رابط بحلقة <code>forEach</code>:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6613_9" style="">
<code class="hljs php"><span class="hljs-keyword"><span class="kwd">var</span></span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">forEach</span></span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">function</span></span><span class="pln"> </span><span class="hljs-params"><span class="pun">(</span><span class="pln">array</span><span class="pun">,</span><span class="pln"> callback</span><span class="pun">,</span><span class="pln"> scope</span><span class="pun">)</span></span><span class="pln"> </span><span class="pun">{</span></span><span class="pln">
  </span><span class="hljs-keyword"><span class="kwd">for</span></span><span class="pln"> </span><span class="pun">(</span><span class="hljs-keyword"><span class="kwd">var</span></span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">array</span></span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    callback</span><span class="pun">.</span><span class="pln">call</span><span class="pun">(</span><span class="pln">scope</span><span class="pun">,</span><span class="pln"> i</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-keyword"><span class="pln">array</span></span><span class="pun">[</span><span class="pln">i</span><span class="pun">]);</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">};</span></code></pre>

<p>
	ثم سأُحدِّد جميع الروابط، وأرى ما هو العنصر التي تشير إليه، ومن ثم سأطبِّق <code>scrollTo</code> عند النقر عليها:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6613_9" style="">
<code class="hljs php"><span class="hljs-keyword"><span class="kwd">var</span></span><span class="pln"> anchorLinks </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelectorAll</span><span class="pun">(</span><span class="hljs-string"><span class="str">"a[href^='#']"</span></span><span class="pun">);</span><span class="pln">
</span><span class="hljs-keyword"><span class="kwd">if</span></span><span class="pln"> </span><span class="pun">(</span><span class="pln">window</span><span class="pun">.</span><span class="pln">scrollTo</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="hljs-keyword"><span class="pln">forEach</span></span><span class="pun">(</span><span class="pln">anchorLinks</span><span class="pun">,</span><span class="pln"> </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">function</span></span><span class="hljs-params"><span class="pun">(</span><span class="pln">index</span><span class="pun">,</span><span class="pln"> element</span><span class="pun">)</span></span><span class="pln"> </span><span class="pun">{</span></span><span class="pln">
        </span><span class="hljs-keyword"><span class="kwd">var</span></span><span class="pln"> target </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="pln">element</span><span class="pun">.</span><span class="pln">getAttribute</span><span class="pun">(</span><span class="hljs-string"><span class="str">"href"</span></span><span class="pun">).</span><span class="pln">substring</span><span class="pun">(</span><span class="hljs-number"><span class="lit">1</span></span><span class="pun">));</span><span class="pln">
        element</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="hljs-string"><span class="str">"click"</span></span><span class="pun">,</span><span class="pln"> </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">function</span></span><span class="hljs-params"><span class="pun">(</span><span class="pln">el</span><span class="pun">)</span></span><span class="pln"> </span><span class="pun">{</span></span><span class="pln">
            el</span><span class="pun">.</span><span class="pln">preventDefault</span><span class="pun">();</span><span class="pln">
            window</span><span class="pun">.</span><span class="pln">scrollTo</span><span class="pun">(</span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">,</span><span class="pln"> target</span><span class="pun">.</span><span class="pln">offsetTop</span><span class="pun">);</span><span class="pln"> 
        </span><span class="pun">})</span><span class="pln">
    </span><span class="pun">});</span><span class="pln">
</span><span class="pun">}</span></code></pre>

<p>
	لاحظ أنَّ هذا قد يتطلب وضع الخاصية <code>scroll-behavior</code> لعنصر <code>body</code> كما سبق ذكره.
</p>

<h3 id="دعم-المتصفحات">
	دعم المتصفحات
</h3>

<p>
	هنالك إشكالية وحيدة عند استخدام هذه الطريقة في الوقت الراهن ألا وهي دعم المتصفحات؛ حيث تعمل الدالة <code>window.scrollTo</code> في متصفحات الويب الحديثة.<br>
	ولأننا كتبنا السكربت بطريقة تجعله يتحقق أولًا من دعم المتصفح للدالة <code>scrollTo</code>، فستعمل الصفحة بشكل سليم على المتصفحات القديمة إلا أنَّ التمرير سيكون فوريًا وليس سلسًا؛ ويمكنك أن تستعمل إحدى الإضافات أو الطرائق الأخرى لدعم المتصفحات القديمة.
</p>

<h2 id="تطبيق-تأثير-عدم-الوضوح-على-المحتوى-خلف-شريط-الانتقال">
	تطبيق تأثير عدم الوضوح على المحتوى خلف شريط الانتقال
</h2>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="22954" href="https://academy.hsoub.com/uploads/monthly_2017_04/3-EasyScrollBehindBluredNavigationBar.jpg.c793be6d946c0cb7f60c24162db29383.jpg" rel=""><img alt="3-EasyScrollBehindBluredNavigationBar.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="22954" data-unique="a3j154ne6" src="https://academy.hsoub.com/uploads/monthly_2017_04/3-EasyScrollBehindBluredNavigationBar.thumb.jpg.ced2dac4ad79fa0b0b0112af3c01157e.jpg"></a>
</p>

<p>
	(<a href="https://codepen.io/dudleystorey/pen/RNMbGG" rel="external nofollow">تجربة حية</a>)<br>
	أحد أنماط تصميم الواجهات الشائعة خصوصًا بعد إصدار نسخة iOS 7 هو شريط الانتقال الذي تظهر محتويات الصفحة التي خلفه مشوشةً؛ ربما تظن أنَّ تطبيق المُرشِّح blur في CSS هو الطريقة السهلة والواضحة لتطبيق هذا التأثير في صفحة ويب، وهذا صحيحٌ إلا أنَّ هنالك إشكالية: تأثيرات CSS ستُطبَّق على المحتوى داخل العنصر وليس خلفه. أي لا يوجد تأثير من تأثيرات CSS الذي يمكن أن يؤدي إلى تشويش العناصر خلفه، باستثناء خاصية اختبارية متوافرة في متصفح Safari 9 فقط باسم <code>‎-webkit-backdrop-filter-</code>؛ لكن بالطبع سنجد حلًا!
</p>

<h3 id="إنشاء-شريط-الانتقال">
	إنشاء شريط الانتقال
</h3>

<p>
	الشريط نفسه هو عنصرٌ فارغٌ يملك القيمة <code>fixed</code> للخاصية <code>position</code>، وعناصر التنقل تأتي «فوق» ذاك العنصر باستعمال نفس الأبعاد. سأكتبُ ذلك باستخدامSass لأنَّها أقصر:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6613_9" style="">
<code class="hljs scss"><span class="hljs-id"><span class="com">#blurrycontent</span></span><span class="com"> {</span><span class="pln">
    </span><span class="hljs-attribute"><span class="pln">padding</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">1</span></span><span class="lit">rem</span><span class="pun">;</span></span><span class="pln">
    </span><span class="hljs-attribute"><span class="pln">top</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">;</span></span><span class="pln"> </span><span class="hljs-attribute"><span class="pln">left</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">0</span></span><span class="pun">;</span></span><span class="pln">
    </span><span class="hljs-attribute"><span class="pln">width</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">100</span></span><span class="pun">%;</span></span><span class="pln">
    </span><span class="hljs-attribute"><span class="pln">height</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> </span><span class="hljs-number"><span class="lit">5</span></span><span class="lit">rem</span><span class="pun">;</span></span><span class="pln">
    </span><span class="hljs-attribute"><span class="pln">overflow</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> hidden</span><span class="pun">;</span></span><span class="pln">
    </span><span class="hljs-attribute"><span class="pln">position</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> </span><span class="kwd">fixed</span><span class="pun">;</span></span><span class="pln">
    </span><span class="hljs-attribute"><span class="pln">filter</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> blur</span><span class="pun">(</span><span class="hljs-number"><span class="lit">4</span></span><span class="lit">px</span><span class="pun">);</span></span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="hljs-tag"><span class="pln">nav</span></span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="hljs-at_rule"><span class="lit">@</span><span class="hljs-keyword"><span class="lit">extend</span></span><span class="pln"> </span><span class="hljs-hexcolor"><span class="com">#b</span></span><span class="com">lurrycontent;</span></span><span class="pln">
    </span><span class="hljs-attribute"><span class="pln">filter</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> none</span><span class="pun">;</span></span><span class="pln">
    </span><span class="hljs-attribute"><span class="pln">text</span><span class="pun">-</span><span class="pln">align</span></span><span class="hljs-value"><span class="pun">:</span><span class="pln"> right</span><span class="pun">;</span></span><span class="pln">
</span><span class="pun">}</span></code></pre>

<p>
	يجب أن تتواجد بقية الصفحة داخل العنصر <code>&lt;main&gt;</code>، وليس داخل العنصر <code>&lt;body&gt;</code>، وذلك لأسبابٍ سنوضِّحها بعد لحظات:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6613_9" style="">
<code class="hljs livecodeserver"><span class="tag">&lt;main</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="hljs-string"><span class="atv">"content"</span></span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;h1&gt;</span><span class="pln">London</span><span class="tag">&lt;/h1&gt;</span><span class="pln">
    </span><span class="tag">&lt;p&gt;</span><span class="pln">With roots </span><span class="hljs-keyword"><span class="pln">at</span></span><span class="pln"> least </span><span class="hljs-number"><span class="pln">7</span></span><span class="pln">,</span><span class="hljs-number"><span class="pln">000</span></span><span class="pln"> years old, London is </span><span class="hljs-operator"><span class="pln">an</span></span><span class="pln"> accretion </span><span class="hljs-operator"><span class="pln">of</span></span><span class="pln"> artifacts old </span><span class="hljs-operator"><span class="pln">and</span></span><span class="pln"> </span><span class="hljs-built_in"><span class="pln">new</span></span><span class="pln">, </span><span class="hljs-built_in"><span class="pln">from</span></span><span class="pln"> </span><span class="hljs-operator"><span class="pln">the</span></span><span class="pln"> remnants </span><span class="hljs-operator"><span class="pln">of</span></span><span class="pln"> wooden Neolithic settlements buried </span><span class="hljs-operator"><span class="pln">in</span></span><span class="pln"> </span><span class="hljs-operator"><span class="pln">the</span></span><span class="pln"> mud </span><span class="hljs-operator"><span class="pln">of</span></span><span class="pln"> </span><span class="hljs-operator"><span class="pln">the</span></span><span class="pln"> Thames </span><span class="hljs-built_in"><span class="pln">to</span></span><span class="pln"> gleaming </span><span class="hljs-number"><span class="pln">21</span></span><span class="pln">st century spires </span><span class="hljs-operator"><span class="pln">of</span></span><span class="pln"> glass </span><span class="hljs-operator"><span class="pln">and</span></span><span class="pln"> steel…
</span><span class="tag">&lt;/main&gt;</span></code></pre>

<p>
	ولأنَّ العنصرين <code>‎#blurrycontent</code> و <code>&lt;nav&gt;</code> متموضعَين فوق بعضهما في مكانٍ ثابتٍ في أعلى الشاشة، فيجب تنسيق العنصر <code>&lt;main&gt;</code> لكي يأخذ مكان بقية المحتوى:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6613_9" style="">
<code class="hljs css"><span class="hljs-tag"><span class="pln">main</span></span><span class="pln"> </span><span class="hljs-rules"><span class="pun">{</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">margin</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">0</span></span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">background</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-function"><span class="pln">url</span><span class="pun">(</span><span class="pln">london_background</span><span class="pun">.</span><span class="pln">jpg</span><span class="pun">)</span></span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">background</span><span class="pun">-</span><span class="pln">size</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> cover</span></span></span><span class="pun">;</span><span class="pln">
    </span><span class="hljs-rule"><span class="hljs-attribute"><span class="pln">padding</span></span><span class="pun">:</span><span class="hljs-value"><span class="pln"> </span><span class="hljs-number"><span class="lit">2</span></span><span class="lit">rem</span></span></span><span class="pun">;</span><span class="pln">
</span><span class="hljs-rule"><span class="pun">}</span></span></span></code></pre>

<p>
	حسنًا، تبدو الصفحة جيدةً، لكننا لم نرَ أيّة تأثيرات في منطقة شريط التنقل عندما يتم التمرير؛ وهذا ما سنفعله في الخطوة الآتية.
</p>

<h3 id="إنشاء-تأثير-الزجاج">
	إنشاء تأثير «الزجاج»!
</h3>

<p>
	كما ذكرتُ في البداية، لا تُطبّق تأثيرات CSS إلا على المحتوى الموجود داخل العنصر، وليس تحته؛ لذا سنأخذ نسخةً من العنصر <code>&lt;main&gt;</code> ونضعها داخل العنصر <code>‎#blurrycontent</code> باستخدام الدالة <code>cloneNode</code> عبر سكربت موجود في أسفل الصفحة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6613_9" style="">
<code class="hljs avrasm"><span class="kwd">var</span><span class="pln"> pageContent </span><span class="pun">=</span><span class="pln"> document</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">getElementById</span></span><span class="pun">(</span><span class="hljs-string"><span class="str">"content"</span></span><span class="pun">),</span><span class="pln">
pagecopy </span><span class="pun">=</span><span class="pln"> pageContent</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">cloneNode</span></span><span class="pun">(</span><span class="kwd">true</span><span class="pun">),</span><span class="pln">
blurryContent </span><span class="pun">=</span><span class="pln"> document</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">getElementById</span></span><span class="pun">(</span><span class="hljs-string"><span class="str">"blurrycontent"</span></span><span class="pun">)</span><span class="hljs-comment"><span class="pun">;</span></span><span class="pln">
blurryContent</span><span class="hljs-preprocessor"><span class="pun">.</span><span class="pln">appendChild</span></span><span class="pun">(</span><span class="pln">pagecopy</span><span class="pun">)</span><span class="hljs-comment"><span class="pun">;</span></span></code></pre>

<p>
	قد لا تستطيع ملاحظة التأثير في هذه المرحلة، لأنَّ المحتوى الموجود داخل العنصر <code>‎#blurrycontent</code> لن يُمرَّر مع بقية المستند، وعلينا مزامنة حركتهما بإضافة السطر الآتي إلى السكربت:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6613_9" style="">
<code class="hljs javascript"><span class="pln">window</span><span class="pun">.</span><span class="pln">onscroll </span><span class="pun">=</span><span class="pln"> </span><span class="hljs-function"><span class="hljs-keyword"><span class="kwd">function</span></span><span class="hljs-params"><span class="pun">()</span></span><span class="pln"> </span><span class="pun">{</span></span><span class="pln"> 
        blurryContent</span><span class="pun">.</span><span class="pln">scrollTop </span><span class="pun">=</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">pageYOffset</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></code></pre>

<p>
	بعد أن ربطناهما مع بعضهما بعضًا، فيمكننا أن نُمرِّر الصفحة وسنحصل على نفس المحتوى الموجود تحت شريط التنقل في عنصر <code>‎#blurrycontent</code> لكنه مشوش. ولأنَّ العنصر <code>&lt;nav&gt;</code> غير موجود داخل العنصر <code>‎#blurrycontent</code> فلن يخضع لتأثير عدم الوضوح.
</p>

<h3 id="محدوديات-هذه-الطريقة">
	محدوديات هذه الطريقة
</h3>

<p>
	كما هو واضح، إنشاء نسخة من محتوى الصفحة وتطبيق تأثير عدم الوضوح عليها سيؤدي إلى عبءٍ إضافيٍ على المتصفح وعلى المعالج الرسومي، لذا كن حذرًا في ذلك وقدِّر كمية المحتوى الموجود ضمن العنصر <code>&lt;main&gt;</code> قبل نسخه. الدالة <code>cloneNode</code> تنسخ العنصر نسخًا حيًا، أي أنَّ أيّة تعديلات على العنصر الأصلي ستُطبَّق أيضًا على العنصر المنسوخ، لكن ربما تلاحظ تأثيرًا بسيطًا حتى تتم مزامنة كلا النسختين.<br>
	هذه أربع نقاط أخيرة يجب ملاحظتها:
</p>

<ul>
<li>
		لأنَّ بعض إصدارات متصفح Internet Explorer لا تدعم تأثيرات CSS (وأوقف المتصفح دعم النسخة الخاصة به من هذا التأثير، والتي كانت متاحةً في الإصدارات القديمة منه)، فلن تلاحظ أيّة تغييرات في شريط التنقل في متصفح IE.
	</li>
	<li>
		يجب أن تتجنب استخدام العناصر ذات الموضع الثابت (<code>fixed</code>) في صفحات الويب على الهواتف الذكية والأجهزة اللوحية، فمنذ فترةٍ قريبةٍ كانت طريقة تعامل متصفحات الهواتف مع <code>position: fixed</code> سيئةً، وسيتم حجز مساحة من الشاشة الصغيرة. وصحيحٌ أنَّ هذا التأثير مستوحى من أحد أنظمة الهواتف، ألا أنَّه من الأفضل إيقافه في الشاشات الصغيرة باستخدام مجموعة من media queries (أو يمكنك أن تصمم الموقع للهواتف أولًا [mobile-first] ولا تُشغِّل التأثير حتى تصبح الشاشة بمقاسٍ معيّن).
	</li>
	<li>
		يجب أخذ قابلية الوصول (Accessibility) بعين الاعتبار عند إنشاء مثل هذا التأثير، فستُفسِّر قارئات الشاشة شجرة DOM، وليس ما تراه على الشاشة، وهذا يعني أنَّ قارئات الشاشة ستحصل على نسختين من محتوى الصفحة افتراضيًا، ولتنجب ذلك فسأضع <code>aria-hidden="true"‎</code> في العنصر <code>‎#blurrycontent</code>:
	</li>
</ul>
<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_6613_9" style="">
<code class="hljs applescript"><span class="tag">&lt;</span><span class="hljs-keyword"><span class="tag">div</span></span><span class="pln"> </span><span class="hljs-property"><span class="atn">id</span></span><span class="pun">=</span><span class="hljs-string"><span class="atv">"blurrycontent"</span></span><span class="pln"> </span><span class="atn">aria-hidden</span><span class="pun">=</span><span class="hljs-string"><span class="atv">"true"</span></span><span class="tag">&gt;&lt;/</span><span class="hljs-keyword"><span class="tag">div</span></span><span class="tag">&gt;</span></code></pre>

<p>
	وبهذا سترى قارئات الشاشة النسخةَ الأصلية من الصفحة فقط دونًا عن النسخة الموجودة في العنصر <code>‎#blurrycontent</code>.
</p>

<ul>
<li>
		يجب أن تكون حذرًا عند نسخ العناصر التي لها الخاصية <code>id</code>، فقد يؤدي تكرار قيم الخاصية <code>id</code> إلى تضاربات ومشاكل في CSS و JavaScript.
	</li>
</ul>
<p>
	ترجمة وبتصرّف للمقالات <a href="http://thenewcode.com/950/Background-Reveal-Scroll-In-Pure-CSS" rel="external nofollow">Background Reveal Scroll In Pure CSS</a>و <a href="http://thenewcode.com/507/Smooth-Page-Scroll-in-5-Lines-of-JavaScript" rel="external nofollow">Smooth Page Scroll in 5 Lines of JavaScript</a> و <a href="http://thenewcode.com/990/Scroll-Behind-Blurred-Site-Navigation-Bar" rel="external nofollow">Scroll-Behind Blurred Site Navigation Bar</a>لصاحبها Dudley Storey
</p>
]]></description><guid isPermaLink="false">474</guid><pubDate>Wed, 30 Nov 2016 21:00:00 +0000</pubDate></item><item><title>&#x62A;&#x623;&#x62B;&#x64A;&#x631;&#x627;&#x62A; &#x627;&#x644;&#x62A;&#x645;&#x631;&#x64A;&#x631; &#x641;&#x64A; &#x635;&#x641;&#x62D;&#x627;&#x62A; &#x627;&#x644;&#x648;&#x64A;&#x628; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; Javascript &#x648;CSS&#x2013; &#x627;&#x644;&#x62C;&#x632;&#x621; &#x627;&#x644;&#x623;&#x648;&#x644;</title><link>https://academy.hsoub.com/programming/javascript/%D8%AA%D8%A3%D8%AB%D9%8A%D8%B1%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D9%85%D8%B1%D9%8A%D8%B1-%D9%81%D9%8A-%D8%B5%D9%81%D8%AD%D8%A7%D8%AA-%D8%A7%D9%84%D9%88%D9%8A%D8%A8-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-javascript-%D9%88css%E2%80%93-%D8%A7%D9%84%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%A3%D9%88%D9%84-r400/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2017_04/11.jpg.e9e3ba43fc2c9166d4ea650568eab5bb.jpg" /></p>

<p id="تأثيرات-التمرير-في-صفحات-الويب-باستخدام-javascript-وcss-الجزء-الأول">
	أهلًا بك في هذه السلسلة التي تتحدث عن تأثيرات التمرير (Scrolling Effects)، سنستعرض في هذه السلسلة عددًا من تأثيرات التمرير وسنشرح آلية عملها وسنجرِّبها عمليًا.<br>
	يمكننا الاستفادة من الحدث <code>scroll</code> في JavaScript لإجراء تأثيرات عند تمرير صفحة الويب؛ لكن إن فعلنا ذلك دون إتقان فالنتيجة كارثية، أما إذا أحسنا صنعنا فيمكن لتأثيرات التمرير أن تبهر الزوار وتشعرهم أنَّ موقعك مميز.<br>
	هذه هي المقالة الأولى في هذه السلسلة، والتي تتضمن التأثيرات الآتية:
</p>

<ul>
<li>
		إخفاء صورة خلفية تدريجيًا عند التمرير
	</li>
	<li>
		توضيح الصورة عند التمرير
	</li>
	<li>
		تدوير العناصر عند التمرير
	</li>
	<li>
		تأثير اختلاف المظهر parallax
	</li>
</ul>
<p>
	أما المقالة الثانية والثالثة فهي تتضمن التأثيرات الآتية:
</p>

<ul>
<li>
		إظهار صورة الخلفية عند التمرير باستخدام CSS فقط
	</li>
	<li>
		تمرير سلس للصفحة
	</li>
	<li>
		تطبيق تأثير عدم الوضوح على المحتوى خلف شريط الانتقال
	</li>
	<li>
		إنشاء عنصر قابل للتمرير مع إمكانية وصول مخصصة من لوحة المفاتيح
	</li>
	<li>
		تأثير غروب الشمس باستخدام SVG
	</li>
	<li>
		إظهار فيديو في الخلفية
	</li>
	<li>
		صور متحركة بتأثير parallax باستخدام CSS 3D و JavaScript
	</li>
</ul>
<p>
	سأقدِّم لك في بداية كل قسم رابطًا لتجربة المثال تجربةً حيةً على المتصفح. سيسهل عليك كثيرًا أن تفهم الشرح والشيفرات بعد تجربتك للتأثير.
</p>

<h2 id="إخفاء-صورة-خلفية-تدريجيا-عند-التمرير">
	إخفاء صورة خلفية تدريجيًا عند التمرير
</h2>

<p>
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="20480" href="https://academy.hsoub.com/uploads/monthly_2016_12/1-ResponsiveBackgroundImageFadeonScroll.jpg.1fe5f3e10ff4367006fda74db503b957.jpg" rel=""><img alt="1-ResponsiveBackgroundImageFadeonScroll.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="20480" data-unique="9ek5g0sk7" src="https://academy.hsoub.com/uploads/monthly_2016_12/1-ResponsiveBackgroundImageFadeonScroll.thumb.jpg.a5657f67ca093effde3492cb432d3124.jpg" style=""></a>
</p>

<p style="text-align: center;">
	(<a href="https://codepen.io/dudleystorey/pen/RRwryd" rel="external nofollow">تجربة حية</a>)
</p>

<p>
	<br>
	إذا كنتَ مِن مَن يستعملون صورًا كخلفية لكامل صفحة الويب، فاستخدام تأثير إخفاء تلك الصورة تدريجيًا عند التمرير هو أمرٌ حسن، حيث يمكّنك ذلك من استخدام أيّة صورة كخلفية دون التأثير على وضوح العناصر أو قابلية قراءة النص.<br>
	ولعدم قدرة CSS على الاستجابة مباشرةً إلى موضع شريط التمرير، فنحن بحاجةٍ إلى استخدام بعض شيفرات JavaScript لمعرفة موضع التمرير لأحد العناصر. التقنية التي سأشرحها لك هنا سنستخدم فيها أنماط CSS أيضًا لإنشاء تأثير الإخفاء والتي ستُحدَّث ديناميكيًا عبر JavaScript.
</p>

<h3 id="طريقة-التفافية-للتعويض-عن-عدم-وجود-الخاصية-background-opacity">
	طريقة التفافية للتعويض عن عدم وجود الخاصية background-opacity
</h3>

<p>
	للأسف لا يوجد لحد الآن خاصية باسم background-opacity لتحديد شفافية الخلفية؛ لكن من الممكن إنشاء التأثير عبر استخدام ميزة تعدد الخلفيات في CSS: حيث سنضع الصورة كطبقة (layer)، ثم الطبقة الثانية هي تدرجٌ لوني سنستخدم في ألوانه الشفافية alpha. لذا ستبدو شيفرة CSS كالآتي:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_2183_8">
<span class="pln">body </span><span class="pun">{</span><span class="pln">
    background</span><span class="pun">:</span><span class="pln"> linear</span><span class="pun">-</span><span class="pln">gradient</span><span class="pun">(</span><span class="pln">rgba</span><span class="pun">(</span><span class="lit">255</span><span class="pun">,</span><span class="pln"> </span><span class="lit">255</span><span class="pun">,</span><span class="pln"> </span><span class="lit">255</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">),</span><span class="pln"> 
        rgba</span><span class="pun">(</span><span class="lit">255</span><span class="pun">,</span><span class="pln"> </span><span class="lit">255</span><span class="pun">,</span><span class="pln"> </span><span class="lit">255</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)),</span><span class="pln"> url</span><span class="pun">(</span><span class="pln">times</span><span class="pun">-</span><span class="pln">square</span><span class="pun">-</span><span class="pln">perspective</span><span class="pun">.</span><span class="pln">jpg</span><span class="pun">);</span><span class="pln">
    background</span><span class="pun">-</span><span class="pln">repeat</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">no</span><span class="pun">-</span><span class="pln">repeat</span><span class="pun">;</span><span class="pln">
    background</span><span class="pun">-</span><span class="pln">attachment</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">fixed</span><span class="pln"> </span><span class="pun">!</span><span class="pln">important</span><span class="pun">;</span><span class="pln">
    background</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%</span><span class="pln"> </span><span class="pun">!</span><span class="pln">important</span><span class="pun">;</span><span class="pln">
    background</span><span class="pun">-</span><span class="pln">position</span><span class="pun">:</span><span class="pln"> center top </span><span class="pun">!</span><span class="pln">important</span><span class="pun">;</span><span class="pln">
    padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1rem</span><span class="pun">;</span><span class="pln">
    padding</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">45</span><span class="pun">%;</span><span class="pln">
    color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#fff;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	التدرج اللوني (الذي سيتم وضعه فوق الصورة، لأنَّه عُرِّفَ أولًا) غير ظاهر حاليًا، لأنَّ قيمة الشفافية alpha هي 0 للونين المشكلين للتدرج. استخدمنا الكلمة المفتاحية <code>‎!important</code> للتأكّد أنَّ شيفرة JavaScript –التي سنُطبِّقها بعد قليل– لن تتمكن من إلغاء قيم خاصيات CSS السابقة.<br>
	شيفرة HTML تحتوي على ما يلي:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2183_10">
<span class="tag">&lt;h1&gt;</span><span class="pln">New York Stories</span><span class="tag">&lt;/h1&gt;</span><span class="pln">
    </span><span class="tag">&lt;p&gt;</span><span class="pln">In my younger and more vulnerable years…</span></pre>

<p>
	في النهاية، علينا وضع العنصر h1 في الأعلى:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_2183_13">
<span class="pln">h1 </span><span class="pun">{</span><span class="pln">
    text</span><span class="pun">-</span><span class="pln">shadow</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">5px</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0.5</span><span class="pun">);</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">4rem</span><span class="pun">;</span><span class="pln"> color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#fff;</span><span class="pln">
    line</span><span class="pun">-</span><span class="pln">height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1</span><span class="pun">;</span><span class="pln"> position</span><span class="pun">:</span><span class="pln"> absolute</span><span class="pun">;</span><span class="pln">
    top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10px</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	ولكي تصبح الفقرة قابلةً للقراءة، فعلينا أن نحوِّل التدرج اللوني إلى اللون الأبيض تمامًا، مما يؤدي إلى إخفاء صورة الخلفية.
</p>

<h3 id="تعديل-التدرجات-اللوني-في-css-باستخدام-javascript">
	تعديل التدرجات اللوني في CSS باستخدام JavaScript
</h3>

<p>
	أضف شيفرة JavaScript الآتية في أسفل الصفحة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2183_15">
<span class="kwd">var</span><span class="pln"> nystories </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">"p"</span><span class="pun">).</span><span class="pln">offsetTop</span><span class="pun">;</span><span class="pln">
window</span><span class="pun">.</span><span class="pln">onscroll </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">window</span><span class="pun">.</span><span class="pln">pageYOffset </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">var</span><span class="pln"> opac </span><span class="pun">=</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">pageYOffset </span><span class="pun">/</span><span class="pln"> nystories</span><span class="pun">;</span><span class="pln">
    document</span><span class="pun">.</span><span class="pln">body</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">background </span><span class="pun">=</span><span class="pln"> </span><span class="str">"linear-gradient(rgba(255, 255, 255, "</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> opac </span><span class="pun">+</span><span class="pln"> </span><span class="str">"),</span><span class="pln"> 
        rgba</span><span class="pun">(</span><span class="lit">255</span><span class="pun">,</span><span class="pln"> </span><span class="lit">255</span><span class="pun">,</span><span class="pln"> </span><span class="lit">255</span><span class="pun">,</span><span class="pln"> </span><span class="str">" + opac + "</span><span class="pun">)),</span><span class="pln"> 
        url</span><span class="pun">(</span><span class="pln">times</span><span class="pun">-</span><span class="pln">square</span><span class="pun">-</span><span class="pln">perspective</span><span class="pun">.</span><span class="pln">jpg</span><span class="pun">)</span><span class="pln"> no</span><span class="pun">-</span><span class="pln">repeat</span><span class="str">";</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	في الشيفرة السابقة، قيمةُ المتغير <code>nystories</code> هي موضع أوّل فقرة في الصفحة. عندما يبدأ المستخدم بالتمرير فستُنشِئ الشيفرة السابقة متغيرًا باسم <code>opac</code> الذي سيُقسِّم الموضع «الحالي» للنافذة على الموضع «البدائي» لأول فقرة. ومن ثم ستُجمَع النتيجة مع قيم rgb لألوان التدرج اللوني مكان قيمة الشفافية alpha، مما يعطي التأثير بإخفاء صورة الخلفية عندما يتم تمرير الصفحة.<br>
	هذا أحد الأمثلة البسيطة عن التمرير، ما زال في جعبتنا المزيد.
</p>

<h2 id="توضيح-الصورة-عند-التمرير">
	توضيح الصورة عند التمرير
</h2>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="20481" href="https://academy.hsoub.com/uploads/monthly_2016_12/2-Scroll-to-FocusForHeroImages.jpg.0ed3686de5d3fa529c8513194328ecbc.jpg" rel=""><img alt="2-Scroll-to-FocusForHeroImages.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="20481" data-unique="7vd0x3032" src="https://academy.hsoub.com/uploads/monthly_2016_12/2-Scroll-to-FocusForHeroImages.thumb.jpg.7bcf461fb5830083e4fe29539ba9a49b.jpg" style=""></a>
</p>

<p style="text-align: center;">
	(<a href="https://codepen.io/dudleystorey/pen/clFJB" rel="external nofollow">تجربة حية</a>)
</p>

<p>
	<br>
	أعجبتني اللمسة الجميلة في تطبيق توتير على هواتف iPhone: عندما تمرّر إلى الأسفل في صفحة «Me» فستصبح صورة الترويسة غير واضحة وسيتم تقريبها. أرى أنَّ من المفيد تقليد هذه التقنية في متصفحات الويب، خصوصًا للصور البارزة التابعة للمقالات…<br>
	شيفرة HTML بسيطة للغاية:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2183_18">
<span class="tag">&lt;article&gt;</span><span class="pln">
    </span><span class="tag">&lt;header&gt;</span><span class="pln">
        </span><span class="tag">&lt;img</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"placid-pond.jpg"</span><span class="pln"> </span><span class="atn">alt</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;/header&gt;</span><span class="pln">
…
</span><span class="tag">&lt;/article&gt;</span></pre>

<p>
	وفي نفس الصفحة سنضيف شيفرة SVG:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2183_20">
<span class="tag">&lt;svg</span><span class="pln"> </span><span class="atn">xmlns</span><span class="pun">=</span><span class="atv">"http://www.w3.org/2000/svg"</span><span class="pln"> </span><span class="atn">width</span><span class="pun">=</span><span class="atv">"0"</span><span class="pln"> </span><span class="atn">height</span><span class="pun">=</span><span class="atv">"0"</span><span class="tag">&gt;</span><span class="pln">
  </span><span class="tag">&lt;filter</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"blur"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;feGaussianBlur</span><span class="pln"> </span><span class="atn">stdDeviation</span><span class="pun">=</span><span class="atv">"0"</span><span class="pln"> </span><span class="tag">/&gt;</span><span class="pln">
  </span><span class="tag">&lt;/filter&gt;</span><span class="pln">
</span><span class="tag">&lt;/svg&gt;</span></pre>

<p>
	الغرض من وضع شيفرة SVG السابقة هو إضافة تأثير عدم الوضوح (blur) في متصفح Firefox، والذي لا يدعم إلى الآن «مُرشّحات CSS» ‏(CSS Filters)؛ لاحظ أنَّ خاصية العرض والارتفاع لعنصر svg لها القيمة 0، لذا لن يؤثِّر على تخطيط الصفحة.<br>
	سنضيف تأثير عدم الوضوح عبر أنماط CSS:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_2183_22">
<span class="pln">header </span><span class="pun">{</span><span class="pln">
    overflow</span><span class="pun">:</span><span class="pln"> hidden</span><span class="pun">;</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
article header img </span><span class="pun">{</span><span class="pln">
    width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%;</span><span class="pln">
    height</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">auto</span><span class="pun">;</span><span class="pln">
    filter</span><span class="pun">:</span><span class="pln"> url</span><span class="pun">(#</span><span class="pln">blur</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	شيفرة JavaScript أكثر تعقيدًا مما سبق. يجب في البداية أن نضع جميع الشيفرات داخل دالة التي ستستدعى عندما يتم التمرير في المتصفح:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2183_24">
<span class="pln">window</span><span class="pun">.</span><span class="pln">onscroll </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">(</span><span class="pln">event</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">  

</span><span class="pun">}</span></pre>

<p>
	سنحتاج إلى الكثير من المعلومات داخل هذه الدالة. المتغيرات التي سنستعملها هي:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2183_26">
<span class="kwd">var</span><span class="pln"> headerImg </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">"article header img"</span><span class="pun">),</span><span class="pln">
headerImgOffset </span><span class="pun">=</span><span class="pln"> headerImg</span><span class="pun">.</span><span class="pln">getBoundingClientRect</span><span class="pun">(),</span><span class="pln">
imgTop </span><span class="pun">=</span><span class="pln"> headerImgOffset</span><span class="pun">.</span><span class="pln">top</span><span class="pun">,</span><span class="pln">
imgBottom </span><span class="pun">=</span><span class="pln"> headerImgOffset</span><span class="pun">.</span><span class="pln">bottom</span><span class="pun">,</span><span class="pln">
imgHeight </span><span class="pun">=</span><span class="pln"> headerImg</span><span class="pun">.</span><span class="pln">offsetHeight</span><span class="pun">,</span><span class="pln">
viewportHeight </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">documentElement</span><span class="pun">.</span><span class="pln">clientHeight</span><span class="pun">,</span><span class="pln">
blur </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">"blur"</span><span class="pun">),</span><span class="pln">
svgblur </span><span class="pun">=</span><span class="pln"> blur</span><span class="pun">.</span><span class="pln">getElementsByTagName</span><span class="pun">(</span><span class="str">"feGaussianBlur"</span><span class="pun">)[</span><span class="lit">0</span><span class="pun">],</span><span class="pln">
topEffectStart </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">abs</span><span class="pun">((</span><span class="pln">viewportHeight </span><span class="pun">–</span><span class="pln"> imgHeight</span><span class="pun">)/</span><span class="lit">5</span><span class="pun">);</span></pre>

<p>
	 
</p>

<p>
	اقرأ الأسطر السابقة بتمعّن، يجب أن تبدو لك المتغيرات منطقيةً:
</p>

<ul>
<li>
		المتغير <code>headerImg</code> يشير إلى صورة الترويسة الموجودة في أعلى المقالة (وللتبسيط، سأعتبر أنَّ الصفحة فيها مقالة وحيدة، وعنصر header وحيد).
	</li>
	<li>
		المتغير <code>headerImgOffset</code> يسمح لنا بالوصول إلى مكان وأبعاد الصورة، وفي حالتنا سنستخدم <code>imgTop</code> و <code>imgBottom</code> و <code>imgHeight</code>.
	</li>
	<li>
		المتغير <code>viewportHeight</code> يمثِّل ارتفاع نافذة المتصفح.
	</li>
	<li>
		المتغير <code>blur</code> يشير إلى شيفرة SVG في الصفحة، أما <code>svgBlur</code> فهو العنصر الذي سيسبِّب تأثير عدم الوضوح في متصفح Firefox.
	</li>
	<li>
		المتغير <code>topEffectStart</code> هو الفرق بين ارتفاع «إطار العرض» (viewport) الحالي وارتفاع الصورة، ومقسومًا على 5. وهذا يعني أنَّ تأثير عدم الوضوح سيبدأ فقط إذا كانت صورة الترويسة في الخُمس العلوي من نافذة المتصفح. استخدمتُ الدالة <code>Math.abs</code> لكي أحصل دومًا على عددٍ موجب، لأنَّ من الممكن أن تكون الصورة «أطول» من ارتفاع إطار العرض الحالي.
	</li>
</ul>
<p>
	بعد توضيح كل ما سبق، فلنضف عبارةً شرطيةً داخل الدالة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2183_28">
<span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">imgTop </span><span class="pun">&lt;</span><span class="pln"> topEffectStart </span><span class="pun">&amp;&amp;</span><span class="pln"> imgBottom </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
    blurFactor </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">abs</span><span class="pun">(</span><span class="pln">imgTop </span><span class="pun">/</span><span class="pln"> </span><span class="lit">100</span><span class="pun">);</span><span class="pln">
    scaleFactor </span><span class="pun">=</span><span class="pln"> </span><span class="lit">1</span><span class="pun">+</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">abs</span><span class="pun">(</span><span class="pln">imgTop </span><span class="pun">/</span><span class="pln"> </span><span class="lit">1000</span><span class="pun">);</span><span class="pln">
    headerImg</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">webkitFilter </span><span class="pun">=</span><span class="pln"> </span><span class="str">"blur("</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> blurFactor </span><span class="pun">+</span><span class="pln"> </span><span class="str">"px)"</span><span class="pun">;</span><span class="pln">
    svgblur</span><span class="pun">.</span><span class="pln">setAttribute</span><span class="pun">(</span><span class="str">"stdDeviation"</span><span class="pun">,</span><span class="pln"> blurFactor</span><span class="pun">);</span><span class="pln">
    headerImg</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">webkitTransform </span><span class="pun">=</span><span class="pln"> </span><span class="str">"scale(scaleFactor)"</span><span class="pun">;</span><span class="pln">
    headerImg</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">transform </span><span class="pun">=</span><span class="pln"> </span><span class="str">"scale(scaleFactor)"</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	هذا يعني إذا كان أعلى الصورة موجودٌ في أول خُمس من نافذة إطار العرض وما زالت الصورةُ معروضةً وظاهرةً للمستخدم، فافعل ما يلي:
</p>

<ul>
<li>
		أخذ الموقع الحالي لأعلى الصورة نسبةً إلى أعلى إطار العرض، وتقسيم الناتج على 100، وتحويل الناتج إلى عدد عشري موجب، وتسمية الناتج باسم <code>blurFactor</code>.
	</li>
	<li>
		وبطريقةٍ مشابهة، سنأخذ الفرق، ونُقسِّمه على 1000 (لأن تغيير المقياس [scale] حساسٌ أكثر من تأثير عدم الوضوح) ومن ثم سنجمع العدد 1 مع الناتج، ونسمِّه <code>scaleFactor</code>.
	</li>
	<li>
		سنُطبِّق <code>blurFactor</code> (بعد إضافة “px” إليه) على صورة الترويسة، وذلك بوضعه كقيمة لمُرشِّح Webkit Blur.
	</li>
	<li>
		وبطريقةٍ مشابهة، سنُغيّر قيمة <code>stdDeviation</code> لنفس قيمة <code>blurFactor</code> وذلك لتطبيق التأثير في متصفح Firefox.
	</li>
	<li>
		في النهاية، سنسند قيمة <code>scaleFactor</code> إلى خاصية <code>transform</code> في CSS لصورة الترويسة.
	</li>
</ul>
<p>
	إحدى ميزات استخدام <code>scale</code> و <code>blur</code> معًا هي القدرة على إخفاء تأثير عدم الوضوح في جوانب الصورة، والتي لا يمكن إخفاؤها حتى باستخدام <code>overflow: hidden</code> في الحالات العادية.<br>
	يمكن استخدام نفس <a href="https://codepen.io/dudleystorey/pen/clFJB" rel="external nofollow">السكربت</a> السابق مع بعض التعديلات لكي يتم التركيز أو توضيح الصورة عندما تكون في منتصف الصفحة، مما يجذب انتباه المستخدم إليها.
</p>

<h2 id="تدوير-العناصر-المسننات-عند-التمرير">
	تدوير العناصر (المسننات) عند التمرير
</h2>

<p>
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="20482" href="https://academy.hsoub.com/uploads/monthly_2016_12/3-RotatePageElementsonScrollwithJavaScript.jpg.b85da6da7cc773b49a1da19248b13f88.jpg" rel=""><img alt="3-RotatePageElementsonScrollwithJavaScript.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="20482" data-unique="dneezswah" src="https://academy.hsoub.com/uploads/monthly_2016_12/3-RotatePageElementsonScrollwithJavaScript.thumb.jpg.9733f5920df800d2170a8809b1f6e909.jpg" style=""></a>
</p>

<p style="text-align: center;">
	(<a href="https://codepen.io/dudleystorey/pen/pgzeor" rel="external nofollow">تجربة حية</a>)
</p>

<p>
	<br>
	سأريك في هذا المثال كيفية تدوير العناصر أثناء تمرير الصفحة باستخدام JavaScript مباشرةً دون أيّة مكتبات خارجية.
</p>

<h3 id="ضبط-المسننات">
	ضبط المسننات
</h3>

<p>
	سيتم وضع المسننين في الصفحة باستخدام قيم <code>id</code> فريدة لكلٍ منهما؛ ولمّا كانا عبارةً عن رسوميات متجهة (vector shapes) فمن المعقول أن نُنشئهما باستخدام SVG:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2183_32">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"gearbox"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;img</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"gear.svg"</span><span class="pln"> </span><span class="atn">alt</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"leftgear"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;img</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"gear.svg"</span><span class="pln"> </span><span class="atn">alt</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"rightgear"</span><span class="tag">&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	هنالك الكثير من الخيارات لطريقة وضع المسننات: ففي أغلبية الأحيان سنستعمل موضعًا ثابتًا لها (أي <code>position: fixed</code>)، ومن الممكن أيضًا وضعها في مكانٍ معيّن ثم سيصبح موقعها ثابتًا عندما يتم التمرير بعدها (أي <code>position: sticky</code>). سأستعمل في هذا المثال flexbox لفصل العناصر، وسأستخدم الواحدات vm لقياسها؛ ويمكن أيضًا أن يكون موضع المسننات static وبالتالي ستختفي المسننات عند تمرير الصفحة.
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_2183_34">
<span class="com">#gearbox {</span><span class="pln">
    display</span><span class="pun">:</span><span class="pln"> flex</span><span class="pun">;</span><span class="pln">
    justify</span><span class="pun">-</span><span class="pln">content</span><span class="pun">:</span><span class="pln"> space</span><span class="pun">-</span><span class="pln">between</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">#leftgear, #rightgear {</span><span class="pln">
    width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">20vw</span><span class="pun">;</span><span class="pln">
    max</span><span class="pun">-</span><span class="pln">width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">20</span><span class="pun">%;</span><span class="pln">
    height</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">auto</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<h3 id="تدوير-المسننات">
	تدوير المسننات
</h3>

<p>
	تدوير العناصر سهلٌ للغاية، كل ما عليك فعله هو إضافة الشيفرة الآتية في أسفل الصفحة:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2183_36">
<span class="kwd">var</span><span class="pln"> leftgear </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">"leftgear"</span><span class="pun">),</span><span class="pln">
rightgear </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">"rightgear"</span><span class="pun">);</span><span class="pln">

window</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"scroll"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    leftgear</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">transform </span><span class="pun">=</span><span class="pln"> </span><span class="str">"rotate("</span><span class="pun">+</span><span class="pln">window</span><span class="pun">.</span><span class="pln">pageYOffset</span><span class="pun">+</span><span class="str">"deg)"</span><span class="pun">;</span><span class="pln">
    rightgear</span><span class="pun">.</span><span class="pln">style</span><span class="pun">.</span><span class="pln">transform </span><span class="pun">=</span><span class="pln"> </span><span class="str">"rotate(-"</span><span class="pun">+</span><span class="pln">window</span><span class="pun">.</span><span class="pln">pageYOffset</span><span class="pun">+</span><span class="str">"deg)"</span><span class="pun">;</span><span class="pln">
</span><span class="pun">});</span></pre>

<p>
	سيدور كل مسنن بنفس مقدار تمرير النافذة مقدرًا بالبكسل والذي سيحوّل إلى درجات. لتسريع أو تبطيء دوران المسننات نسبةً إلى مقدار التمرير، فيمكنك جعل <code>window.pageYOffset</code> جزءًا من تعبيرٍ رياضيٍ بسيط (كالقسمة أو الضرب بالرقم 2 على سبيل المثال).
</p>

<h3 id="تفادي-تعليق-المسننات">
	تفادي «تعليق» المسننات
</h3>

<p>
	مشكلة شائعة مع أيّة تقنية التي تتعامل مع التمرير هي «تعليق» العناصر حيث ستحاول مطابقة مدخلات المستخدم. أسهل حل للتعامل مع هذه الإشكالية هو تحريك العناصر عندما يصبح المتصفح جاهزًا للتعامل مع تلك الحركة، وذلك عبر <code>requestAnimationFrame</code>. ولفعل ذلك سنُجعل الدالة <code>addEventListener</code> تستمع إلى حدث خاص (custom event):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2183_39">
<span class="pln">window</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"optimizedScroll"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="pun">…</span><span class="pln">
</span><span class="pun">})</span></pre>

<p>
	وقبل دالة معالجة الحدث، أضف دالةً مجهولةً (anonymous function):
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2183_41">
<span class="pun">;(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">var</span><span class="pln"> throttle </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(</span><span class="pln">type</span><span class="pun">,</span><span class="pln"> name</span><span class="pun">,</span><span class="pln"> obj</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        </span><span class="kwd">var</span><span class="pln"> obj </span><span class="pun">=</span><span class="pln"> obj </span><span class="pun">||</span><span class="pln"> window</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">var</span><span class="pln"> running </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
        </span><span class="kwd">var</span><span class="pln"> func </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
            </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">running</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="kwd">return</span><span class="pun">;</span><span class="pln"> </span><span class="pun">}</span><span class="pln">
            running </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
            requestAnimationFrame</span><span class="pun">(</span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
                obj</span><span class="pun">.</span><span class="pln">dispatchEvent</span><span class="pun">(</span><span class="kwd">new</span><span class="pln"> </span><span class="typ">CustomEvent</span><span class="pun">(</span><span class="pln">name</span><span class="pun">));</span><span class="pln">
                running </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
            </span><span class="pun">});</span><span class="pln">
        </span><span class="pun">};</span><span class="pln">
        obj</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="pln">type</span><span class="pun">,</span><span class="pln"> func</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">};</span><span class="pln">
    throttle </span><span class="pun">(</span><span class="str">"scroll"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"optimizedScroll"</span><span class="pun">);</span><span class="pln">
</span><span class="pun">})();</span></pre>

<h2 id="طريقة-سهلة-لإنشاء-تأثير-اختلاف-المظهر">
	طريقة سهلة لإنشاء تأثير اختلاف المظهر
</h2>

<p style="text-align: center;">
	<a class="ipsAttachLink ipsAttachLink_image" data-fileid="20483" href="https://academy.hsoub.com/uploads/monthly_2016_12/4-Simple-EM-Parallax.jpg.13ed5d2cce739a5cabd82c1a9c774f88.jpg" rel=""><img alt="4-Simple-EM-Parallax.jpg" class="ipsImage ipsImage_thumbnailed" data-fileid="20483" data-unique="wzzj4cgac" src="https://academy.hsoub.com/uploads/monthly_2016_12/4-Simple-EM-Parallax.thumb.jpg.82263c7a995b08507f5a83aac1200d8c.jpg" style=""></a>
</p>

<p style="text-align: center;">
	(<a href="https://codepen.io/dudleystorey/pen/PzYrZO" rel="external nofollow">تجربة حية</a>)
</p>

<p>
	<br>
	نَشَرَ «Adam Mustill» تقنيةً ذكيةً جدًا لإنشاء تأثير اختلاف المظهر (Parallax) عبر تعديل واحدة root em. يتساءل الكثيرون عن كيفية إنشاء تأثيرات اختلاف المظهر، وارتأيتُ أنَّ هذه الطريقة قد تكون نقطة بداية جيدة لتعلم إنشاء هذا التأثير.<br>
	تأثير اختلاف المظهر (Parallax) يتطلب عادةً عمليات معالجة معقدة لعدد كبير من عناصر DOM المنفصلة، لكن التقنية التي سنستخدمها هنا تُسهِّل علينا معالجة العناصر بتغيير قياسٍ وحيد، وهي تستغل ميزة غريبة بعض الشيء لواحدة القياس <code>em</code>: إذا كان قياس العنصر الأب والعناصر الأبناء بواحدة <code>em</code>، فإن القياس النهائي للأبناء هو ناتج ضربها مع بعضها. وصحيحٌ أنَّ هذا السلوك قد يُسبِّب لنا صداعًا (وهو سببٌ وجيهٌ لاستخدام <code>rem</code> إن استطعنا) إلا أنَّ له ميزتين في هذه الحالة:<br>
	1. وحدة القياس <code>em</code> لها دعم أقوى في المتصفحات نسبةً إلى <code>rem</code>.<br>
	2. تتطلب <code>em</code> وجود عنصر أب، وهذا يعني أنَّ تأثير اختلاف المظهر يمكن أن يُطبَّق على حاوية معيّنة؛ أما في طريقة <code>rem</code> التي ابتكرها Adam، فإنَّ كل شيءٍ موجود في عنصر <code>&lt;body&gt;</code> سيتأثّر بالتمرير إلا إذا اتخذتَ إجراءاتٍ معينةً للحد من ذلك.<br>
	ولقد حسّنتُ أيضًا من شيفرة Adam وجعلتها سطرًا وحيدًا من شيفرات JavaScript، بدلًا من عدِّة أسطر من jQuery، مما يُحسِّن من الأداء.
</p>

<h3 id="شيفرات-html-و-css">
	شيفرات HTML و CSS
</h3>

<p>
	شيفرة HTML لهذا المثال بسيطةٌ جدًا: إذ هنالك ثلاث صور وترويسة داخل عنصر <code>&lt;div&gt;</code>:
</p>

<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_2183_46">
<span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"parallax"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;h1&gt;</span><span class="pln">Simple EM Parallax Technique</span><span class="tag">&lt;/h1&gt;</span><span class="pln">
    </span><span class="tag">&lt;img</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"candles.jpg"</span><span class="pln"> </span><span class="atn">alt</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;img</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"cherry-tree.jpg"</span><span class="pln"> </span><span class="atn">alt</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;img</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"pagoda-surrounded-by-trees.jpg"</span><span class="pln"> </span><span class="atn">alt</span><span class="tag">&gt;</span><span class="pln">
</span><span class="tag">&lt;/div&gt;</span></pre>

<p>
	وأنماط CSS ليست معقدةً أبدًا:
</p>

<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_2183_48">
<span class="com">#parallax {</span><span class="pln">
    background</span><span class="pun">-</span><span class="pln">image</span><span class="pun">:</span><span class="pln"> url</span><span class="pun">(</span><span class="pln">blurred</span><span class="pun">-</span><span class="pln">background</span><span class="pun">-</span><span class="pln">small</span><span class="pun">.</span><span class="pln">jpg</span><span class="pun">);</span><span class="pln">
    background</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> cover</span><span class="pun">;</span><span class="pln">
    padding</span><span class="pun">-</span><span class="pln">top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">62.5</span><span class="pun">%;</span><span class="pln"> 
    overflow</span><span class="pun">:</span><span class="pln"> hidden</span><span class="pun">;</span><span class="pln">
    position</span><span class="pun">:</span><span class="pln"> relative</span><span class="pun">;</span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="pln"> </span><span class="pun">.</span><span class="lit">1em</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">#parallax * { position: absolute; }</span><span class="pln">
</span><span class="com">#parallax img {</span><span class="pln">
    width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">40</span><span class="pun">%;</span><span class="pln"> height</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">auto</span><span class="pun">;</span><span class="pln">
    box</span><span class="pun">-</span><span class="pln">shadow</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">.</span><span class="lit">2em</span><span class="pln"> </span><span class="lit">8px</span><span class="pln"> </span><span class="lit">4px</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0.5</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">#parallax h1 { </span><span class="pln">
    font</span><span class="pun">-</span><span class="pln">size</span><span class="pun">:</span><span class="lit">3rem</span><span class="pun">;</span><span class="pln"> color</span><span class="pun">:</span><span class="pln"> </span><span class="com">#fff; z-index: 2;</span><span class="pln">
    top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> text</span><span class="pun">-</span><span class="pln">transform</span><span class="pun">:</span><span class="pln"> uppercase</span><span class="pun">;</span><span class="pln">
    width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%;</span><span class="pln"> text</span><span class="pun">-</span><span class="pln">align</span><span class="pun">:</span><span class="pln"> center</span><span class="pun">;</span><span class="pln">
    text</span><span class="pun">-</span><span class="pln">shadow</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">.</span><span class="lit">2em</span><span class="pln"> </span><span class="lit">5px</span><span class="pln"> rgba</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0.4</span><span class="pun">);</span><span class="pln"> 
</span><span class="pun">}</span><span class="pln">
</span><span class="com">#parallax img:nth-of-type(1) {</span><span class="pln">
    left</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5</span><span class="pun">%;</span><span class="pln"> bottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">22em</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">#parallax img:nth-of-type(2) {</span><span class="pln">
    left</span><span class="pun">:</span><span class="pln"> </span><span class="lit">28</span><span class="pun">%;</span><span class="pln"> z</span><span class="pun">-</span><span class="pln">index</span><span class="pun">:</span><span class="pln"> </span><span class="lit">3</span><span class="pun">;</span><span class="pln"> bottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">8em</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span><span class="pln">
</span><span class="com">#parallax img:nth-of-type(3) {</span><span class="pln">
    left</span><span class="pun">:</span><span class="pln"> </span><span class="lit">55</span><span class="pun">%;</span><span class="pln"> bottom</span><span class="pun">:</span><span class="pln"> </span><span class="lit">12em</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

<p>
	الأمور المهمة التي يجب ملاحظتها هي القيمة الافتراضية الصغيرة جدًا لقياس الحاوية <code>‎#parallax</code> بواحدة <code>em</code>، بالإضافة إلى قيم <code>bottom</code> لكل صورة، وأنَّ نص الترويسة مقاسٌ بواحدة <code>rem</code> وليس <code>em</code>.
</p>

<h3 id="شيفرة-javascript">
	شيفرة JavaScript
</h3>

<p>
	شيفرة JavaScript هي عبارة عن سطرٍ وحيدٍ فقط يجري تعديلًا على إحدى خاصيات CSS:
</p>

<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_2183_50">
<span class="pln">window</span><span class="pun">.</span><span class="pln">onscroll </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">window</span><span class="pun">.</span><span class="pln">pageYOffset </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
        document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">"parallax"</span><span class="pun">).</span><span class="pln">style</span><span class="pun">.</span><span class="pln">fontSize </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">window</span><span class="pun">.</span><span class="pln">pageYOffset</span><span class="pun">/</span><span class="lit">20</span><span class="pun">)*</span><span class="lit">.1+</span><span class="str">"em"</span><span class="pun">;</span><span class="pln">
        </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span></pre>

<p>
	بشرح مبسّط: سيؤدي التمرير إلى تغيير قيمة الخاصية <code>font-size</code> لحاوية <code>‎#parallax</code>، وهذا التغيير يعتمد على عدد البكسلات التي تم تمريرها، مقسومةً على 20، مضروبةً بقيمة ‎<code>0.1 em</code>‎ والتي هي حجم الخط الأصلي.<br>
	التمرير إلى الأسفل سيؤدي إلى زيادة قيمة الخاصية <code>bottom</code> لكل صورة مما يدفعها نحو الأعلى؛ لكن الترويسة لن تتأثر لأنها مُقاسة بواحدة <code>rem</code>، وهي ذات خاصية <code>z-index</code> مناسبة مما يسمح للصور بالمرور أمامها وخلفها.
</p>

<h2 id="الخلاصة">
	الخلاصة
</h2>

<p>
	استعرضنا التأثيرات السابقة بسرعة، بقي عليك أن تتمعّن بشيفراتها، وتحاول إيجاد استخدامات أخرى للتقنيات التي رأيتها.<br>
	ترجمة وبتصرّف للمقالات:<br><a href="http://thenewcode.com/644/Fade-A-Responsive-Background-Image-On-Scroll" rel="external nofollow">Fade A Responsive Background Image On Scroll</a>
</p>

<p>
	<a href="http://thenewcode.com/808/Scroll-to-Focus-Effect-For-Hero-Images" rel="external nofollow">Scroll-to-Focus Effect For Hero Images</a>
</p>

<p>
	<a href="http://thenewcode.com/279/Rotate-Elements-on-Scroll-with-JavaScript" rel="external nofollow">Rotate Elements on Scroll with JavaScript</a>
</p>

<p>
	<a href="http://thenewcode.com/832/Easy-Parallax-Effects-With-Em" rel="external nofollow">Easy Parallax Effects With Em</a>
</p>

<p>
	لصاحبها Dudley Storey
</p>
]]></description><guid isPermaLink="false">400</guid><pubDate>Tue, 08 Nov 2016 10:40:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x639;&#x627;&#x645;&#x644; &#x645;&#x639; &#x627;&#x644;&#x639;&#x646;&#x635;&#x631; Canvas &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A; (&#x627;&#x644;&#x62A;&#x639;&#x62F;&#x64A;&#x644; &#x639;&#x644;&#x649; &#x627;&#x644;&#x635;&#x648;&#x631;)</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%B9%D9%86%D8%B5%D8%B1-canvas-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-%D8%A7%D9%84%D8%AA%D8%B9%D8%AF%D9%8A%D9%84-%D8%B9%D9%84%D9%89-%D8%A7%D9%84%D8%B5%D9%88%D8%B1-r290/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2016_02/canvas-javascript.png.d6dfb56bb57fd27888bee0bae04e7dda.png" /></p>

<div id="wmd-preview-section-14">
	<p id="التعامل-مع-العنصر-canvas-باستخدام-جافاسكربت-التعديل-على-الصور-والتحولات">
		سنتطرّق في هذا الدّرس إلى طريقة إنشاء رسم بياني باستخدام Canvas قبل أن نتطرّق إلى بعض عمليات التّعديل على الصّور وبعض التّحولات، ثم سنختم بإنشاء معرض جميل للصّور.
	</p>

	<p style="text-align: center;">
		<img alt="canvas-javascript.png" class="ipsImage ipsImage_thumbnailed" data-fileid="13485" data-unique="8vmlhpqhh" src="https://academy.hsoub.com/uploads/monthly_2016_02/canvas-javascript.png.e7d7cdcef8ef5c3870a8f6d3bbbb47fb.png"></p>

	<p>
		أنصحم بالاطّلاع على <a href="https://academy.hsoub.com/search/?tags=js+canvas+101" rel="">المقالات السّابقة</a> حول Canvas هنا على أكاديمية حسوب قبل مواصلة القراءة.
	</p>
</div>

<div id="wmd-preview-section-15">
	<h2 id="رسم-الصور">
		رسم الصور
	</h2>

	<p>
		تُستخدم الدالة<span style="font-family:courier new,courier,monospace;"> ()drawImage</span> لتصيير الكائن <span style="font-family:courier new,courier,monospace;">image</span> على العنصر <span style="font-family:courier new,courier,monospace;">canvas</span>، تأخذ الدالة <span style="font-family:courier new,courier,monospace;">()drawImage</span> عدة أشكال overloaded وذلك بتغيير نوع وعدد المعاملات كما سنرى في الأمثلة المقبلة.
	</p>

	<p>
		الشكل الأول:
	</p>
</div>

<div id="wmd-preview-section-16">
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5464_7">
<span class="pln">drawImage</span><span class="pun">(</span><span class="pln">image</span><span class="pun">,</span><span class="pln"> x</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">)</span></pre>

	<p>
		تقوم برسم <span style="font-family:courier new,courier,monospace;">CanvasImageSource</span> محدّدة بالمعامل <span style="font-family:courier new,courier,monospace;">image</span> في الإحداثيات (x,y).
	</p>

	<h3>
		رسم خط بياني بسيط باستخدام الدالة <span style="font-family:courier new,courier,monospace;">()drawImage</span>
	</h3>

	<p>
		سأعرض مثالًا يستخدم صورة خارجية كخلفية لرسم خط بياني بسيط. يتيح لك استخدام الخلفيات أو backdrops من أن تجعل السكربت الخاص بك أصغر بكثير وتجنب الحاجة لكتابة الشيفرات البرمجية لتوليد الخلفية.
	</p>

	<p>
		سأستخدم في هذا المثال صورة واحدة لذا يمكنني استخدام معالج حدث التحميل load event handler لتنفيذ جمل الرسم. 
	</p>

	<p>
		تقوم الدالة <span style="font-family:courier new,courier,monospace;">()drawImage </span>بوضع صورة الخلفية عند الإحداثيات (0, 0) والمحدّدة بالزاوية اليسارية العليا للعنصر <span style="font-family:courier new,courier,monospace;">canvas</span>.
	</p>
</div>

<div id="wmd-preview-section-17">
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5464_9">
<span class="kwd">function</span><span class="pln"> draw</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">var</span><span class="pln"> ctx </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'canvas'</span><span class="pun">).</span><span class="pln">getContext</span><span class="pun">(</span><span class="str">'2d'</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">var</span><span class="pln"> img </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Image</span><span class="pun">();</span><span class="pln">
  img</span><span class="pun">.</span><span class="pln">onload </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(){</span><span class="pln">
    ctx</span><span class="pun">.</span><span class="pln">drawImage</span><span class="pun">(</span><span class="pln">img</span><span class="pun">,</span><span class="pun">,</span><span class="pun">);</span><span class="pln">
    ctx</span><span class="pun">.</span><span class="pln">beginPath</span><span class="pun">();</span><span class="pln">
    ctx</span><span class="pun">.</span><span class="pln">moveTo</span><span class="pun">(</span><span class="lit">30</span><span class="pun">,</span><span class="lit">96</span><span class="pun">);</span><span class="pln">
    ctx</span><span class="pun">.</span><span class="pln">lineTo</span><span class="pun">(</span><span class="lit">70</span><span class="pun">,</span><span class="lit">66</span><span class="pun">);</span><span class="pln">
    ctx</span><span class="pun">.</span><span class="pln">lineTo</span><span class="pun">(</span><span class="lit">103</span><span class="pun">,</span><span class="lit">76</span><span class="pun">);</span><span class="pln">
    ctx</span><span class="pun">.</span><span class="pln">lineTo</span><span class="pun">(</span><span class="lit">170</span><span class="pun">,</span><span class="lit">15</span><span class="pun">);</span><span class="pln">
    ctx</span><span class="pun">.</span><span class="pln">stroke</span><span class="pun">();</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
  img</span><span class="pun">.</span><span class="pln">src </span><span class="pun">=</span><span class="pln"> </span><span class="str">'https://mdn.mozillademos.org/files/5395/backdrop.png'</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

	<p>
		سيظهر الرسم البياني مع صورة الخلفية على الشكل التالي:
	</p>

	<p style="text-align: center;">
		<img alt="­í©¡ 1.png" class="ipsImage ipsImage_thumbnailed" data-fileid="13469" data-unique="iv4xaiibr" src="https://academy.hsoub.com/uploads/monthly_2016_02/56cca3c7b88ee_1.png.0fae81d2fc33be3bb9f47dc744c70717.png"></p>
</div>

<div id="wmd-preview-section-18">
	<h2 id="التحجيم-scaling">
		التحجيم Scaling
	</h2>

	<p>
		تتيح لك الدالة <span style="font-family:courier new,courier,monospace;">()drawImage</span> تحديد حجم الصور وفق ما ترغب وذلك بإضافة معاملين إضافيين هما الطول والعرض:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3640_7">
<span class="pln">drawImage</span><span class="pun">(</span><span class="pln">image</span><span class="pun">,</span><span class="pln"> x</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">,</span><span class="pln"> width</span><span class="pun">,</span><span class="pln"> height</span><span class="pun">)</span><span class="pln"> </span></pre>

	<p>
		من خلال الخاصيتين <span style="font-family:courier new,courier,monospace;">width</span> و <span style="font-family:courier new,courier,monospace;">height</span> تستطيع إعطاء الحجم المناسب للصورة عند رسمها على الـ <span style="font-family:courier new,courier,monospace;">canvas</span>.
	</p>

	<h3>
		تبليط صورة Tiling an image
	</h3>

	<p>
		في المثال التالي سأستخدم الصورة أدناه وأكررها عدّة مرات على مساحة الـ canvas بعد تحجيمها لتبدو كلوحة جدارية. 
	</p>

	<p>
		سنحتاج لإنشاء حلقتي تكرار واستدعاء الدالة:
	</p>
</div>

<div id="wmd-preview-section-19">
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3640_9">
<span class="pln">drawImage</span><span class="pun">(</span><span class="pln">image</span><span class="pun">,</span><span class="pln"> x</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">,</span><span class="pln"> width</span><span class="pun">,</span><span class="pln"> height</span><span class="pun">)</span></pre>

	<p>
		مع تغيير إحداثيات رسم الصورة كل مرة، ستكرر الحلقة الأولى الصورة عبر الصفوف والحلقة الثانية ستكرر الصورة عبر الأعمدة.
	</p>

	<p>
		سأقوم بتحجيم الصورة إلى ثلث حجمها الأصلي وهو 50x30 بكسل.
	</p>

	<p style="text-align: center;">
		<img alt="­í©¡2.png" class="ipsImage ipsImage_thumbnailed" data-fileid="13470" data-unique="13j1fnhkr" src="https://academy.hsoub.com/uploads/monthly_2016_02/56cca3cb2c3e9_2.png.cde2bfd4f1a1f5510803a109a1c2fde2.png"></p>

	<p>
		<strong>ملاحظة</strong>: قد تبدو الصور ضبابية عند التحجيم وذلك بحسب نوع التحجيم (تكبير أو تصغير) كذلك إن كانت بعض الصور تحوي نصوصًا قد يؤدي تصغير حجمها إلى جعل النصوص غير مقروءة.
	</p>
</div>

<div id="wmd-preview-section-20">
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5464_11">
<span class="kwd">function</span><span class="pln"> draw</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">var</span><span class="pln"> ctx </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'canvas'</span><span class="pun">).</span><span class="pln">getContext</span><span class="pun">(</span><span class="str">'2d'</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">var</span><span class="pln"> img </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Image</span><span class="pun">();</span><span class="pln">
  img</span><span class="pun">.</span><span class="pln">onload </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(){</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">var</span><span class="pln"> i</span><span class="pun">=</span><span class="pun">;</span><span class="pln">i</span><span class="pun">&lt;</span><span class="lit">4</span><span class="pun">;</span><span class="pln">i</span><span class="pun">++){</span><span class="pln">
      </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">var</span><span class="pln"> j</span><span class="pun">=</span><span class="pun">;</span><span class="pln">j</span><span class="pun">&lt;</span><span class="lit">3</span><span class="pun">;</span><span class="pln">j</span><span class="pun">++){</span><span class="pln">
        ctx</span><span class="pun">.</span><span class="pln">drawImage</span><span class="pun">(</span><span class="pln">img</span><span class="pun">,</span><span class="pln">j</span><span class="pun">*</span><span class="lit">50</span><span class="pun">,</span><span class="pln">i</span><span class="pun">*</span><span class="lit">38</span><span class="pun">,</span><span class="lit">50</span><span class="pun">,</span><span class="lit">38</span><span class="pun">);</span><span class="pln">
      </span><span class="pun">}</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">};</span><span class="pln">
  img</span><span class="pun">.</span><span class="pln">src </span><span class="pun">=</span><span class="pln"> </span><span class="str">'https://mdn.mozillademos.org/files/5397/rhino.jpg'</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>

	<p>
		ستظهر الصورة على الشكل التالي:
	</p>

	<p style="text-align: center;">
		<img alt="­í©¡3.png" class="ipsImage ipsImage_thumbnailed" data-fileid="13471" data-unique="p304hv2tp" src="https://academy.hsoub.com/uploads/monthly_2016_02/56cca3cc0f8f1_3.png.bb1fb4e1b4f23adf46e19201dec2ccf7.png"></p>

	<p>
		استعرض المثال على <a href="https://jsfiddle.net/L8g1rpp1/" rel="external nofollow">jsfiddle</a>.
	</p>
</div>

<div id="wmd-preview-section-21">
	<h2 id="التشريح-slicing">
		التشريح Slicing
	</h2>

	<p>
		الاستخدام الثالث والأخير للدالة <span style="font-family:courier new,courier,monospace;">()drawImage</span> هو قص الصور حيث تأخذ الدالة ثمان معاملات:
	</p>
</div>

<div id="wmd-preview-section-22">
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3640_11">
<span class="pln">drawImage</span><span class="pun">(</span><span class="pln">image</span><span class="pun">,</span><span class="pln"> sx</span><span class="pun">,</span><span class="pln"> sy</span><span class="pun">,</span><span class="pln"> sWidth</span><span class="pun">,</span><span class="pln"> sHeight</span><span class="pun">,</span><span class="pln"> dx</span><span class="pun">,</span><span class="pln"> dy</span><span class="pun">,</span><span class="pln"> dWidth</span><span class="pun">,</span><span class="pln"> dHeight</span><span class="pun">)</span></pre>

	<p>
		تحدد الدالة أعلاه مساحة الصورة التي يحددها المستطيل الذي زاويته اليسارية العليا محدّدة بـ (sx, sy) وطوله وعرضه محدّد بـ (sWidth ، sHeight) وتقوم برسمه على الـ canvas في الموضع (dx, dy) وتحدد قيمة التحجيم بالمعاملين (dWidth و dHeight).
	</p>

	<p>
		لتستطيع فهم عمل المعاملات بوضوح انظر للصورة التالية: 
	</p>

	<p style="text-align: center;">
		<img alt="­í©¡ 4.png" class="ipsImage ipsImage_thumbnailed" data-fileid="13472" data-unique="jykac96v0" src="https://academy.hsoub.com/uploads/monthly_2016_02/56cca3cd6a0e0_4.png.3d086e6cc01ac18081eead32ecd13a7d.png"></p>

	<p>
		كما تلاحظ أنه تم تحديد مساحة الصورة المراد قصها اعتمادًا على قيمة المعاملات في الدالة:
	</p>
</div>

<div id="wmd-preview-section-23">
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3640_13">
<span class="pln">drawImage</span><span class="pun">(</span><span class="pln">image</span><span class="pun">,</span><span class="pln"> sx</span><span class="pun">,</span><span class="pln"> sy</span><span class="pun">,</span><span class="pln"> sWidth</span><span class="pun">,</span><span class="pln"> sHeight</span><span class="pun">,</span><span class="pln"> dx</span><span class="pun">,</span><span class="pln"> dy</span><span class="pun">,</span><span class="pln"> dWidth</span><span class="pun">,</span><span class="pln"> dHeight</span><span class="pun">)</span></pre>

	<p>
		تعتبر أداة التشريح او القص مفيدة عندما تريد عمل تراكيب حيث يمكن أن يكون لديك عدة عناصر في ملف صورة واحد وتستخدم الدالة <span style="font-family:courier new,courier,monospace;">()drawImage</span> لتجميعها برسم كامل على سبيل المثال يمكنك أن تقوم بإنشاء رسم بياني كصورة png وتكون كل النصوص اللازمة لوضعها على الرسم البياني موجودة في ملف واعتمادًا على البيانات يمكنك تغيير حجم الرسم البياني بكل سهولة.
	</p>

	<p>
		ميزة أخرى في عمل تركيبات الصور هي أنك لن تكون بحاجة لتحميل كل صورة على حدة والذي يمكن أن يحسن من أداء التحميل.
	</p>
</div>

<div id="wmd-preview-section-24">
	<h2 id="تأطير-الصورة-framing-an-image">
		تأطير الصورة Framing an image
	</h2>

	<p>
		سأقوم بعرض مثال أستخدم فيه نفس الصورة السابقة لقصها باستخدام الدالة <span style="font-family:courier new,courier,monospace;">()drawImage </span>ووضعها بداخل إطار Frame:
	</p>
</div>

<div id="wmd-preview-section-25">
	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_3640_15">
<span class="tag">&lt;html&gt;</span><span class="pln">
 </span><span class="tag">&lt;body</span><span class="pln"> </span><span class="atn">onload</span><span class="pun">=</span><span class="atv">"</span><span class="pln">draw</span><span class="pun">();</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">
   </span><span class="tag">&lt;canvas</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"canvas"</span><span class="pln"> </span><span class="atn">width</span><span class="pun">=</span><span class="atv">"150"</span><span class="pln"> </span><span class="atn">height</span><span class="pun">=</span><span class="atv">"150"</span><span class="tag">&gt;&lt;/canvas&gt;</span><span class="pln">
   </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">style</span><span class="pun">=</span><span class="atv">"</span><span class="pln">display</span><span class="pun">:</span><span class="pln">none</span><span class="pun">;</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln">
     </span><span class="tag">&lt;img</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"source"</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"https://mdn.mozillademos.org/files/5397/rhino.jpg"</span><span class="pln"> </span><span class="atn">width</span><span class="pun">=</span><span class="atv">"300"</span><span class="pln"> </span><span class="atn">height</span><span class="pun">=</span><span class="atv">"227"</span><span class="tag">&gt;</span><span class="pln">
     </span><span class="tag">&lt;img</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"frame"</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"https://mdn.mozillademos.org/files/242/Canvas_picture_frame.png"</span><span class="pln"> </span><span class="atn">width</span><span class="pun">=</span><span class="atv">"132"</span><span class="pln"> </span><span class="atn">height</span><span class="pun">=</span><span class="atv">"150"</span><span class="tag">&gt;</span><span class="pln">
   </span><span class="tag">&lt;/div&gt;</span><span class="pln">
 </span><span class="tag">&lt;/body&gt;</span><span class="pln">
</span><span class="tag">&lt;/html&gt;</span></pre>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_3640_20">
<span class="kwd">function</span><span class="pln"> draw</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
  </span><span class="kwd">var</span><span class="pln"> canvas </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'canvas'</span><span class="pun">);</span><span class="pln">
  </span><span class="kwd">var</span><span class="pln"> ctx </span><span class="pun">=</span><span class="pln"> canvas</span><span class="pun">.</span><span class="pln">getContext</span><span class="pun">(</span><span class="str">'2d'</span><span class="pun">);</span><span class="pln">

  </span><span class="com">// Draw slice</span><span class="pln">
  ctx</span><span class="pun">.</span><span class="pln">drawImage</span><span class="pun">(</span><span class="pln">document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'source'</span><span class="pun">),</span><span class="pln">
                </span><span class="lit">33</span><span class="pun">,</span><span class="pln"> </span><span class="lit">71</span><span class="pun">,</span><span class="pln"> </span><span class="lit">104</span><span class="pun">,</span><span class="pln"> </span><span class="lit">124</span><span class="pun">,</span><span class="pln"> </span><span class="lit">21</span><span class="pun">,</span><span class="pln"> </span><span class="lit">20</span><span class="pun">,</span><span class="pln"> </span><span class="lit">87</span><span class="pun">,</span><span class="pln"> </span><span class="lit">104</span><span class="pun">);</span><span class="pln">

  </span><span class="com">// Draw frame</span><span class="pln">
  ctx</span><span class="pun">.</span><span class="pln">drawImage</span><span class="pun">(</span><span class="pln">document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'frame'</span><span class="pun">),</span><span class="pun">,</span><span class="pun">);</span><span class="pln">
</span><span class="pun">}</span></pre>

	<p>
		ستظهر الصورة على الشكل التالي:
	</p>
</div>

<div id="wmd-preview-section-26">
	<p style="text-align: center;">
		<img alt="­í©¡5.png" class="ipsImage ipsImage_thumbnailed" data-fileid="13473" data-unique="qij4io2rz" src="https://academy.hsoub.com/uploads/monthly_2016_02/56cca3d27bba3_5.png.62c920df5b7c1e8bbc86209b268b7cb7.png"></p>

	<p>
		استعرض المثال على <a href="https://jsfiddle.net/qbfrjw49/" rel="external nofollow">jsfiddle</a>.
	</p>
</div>

<div id="wmd-preview-section-27">
	<h2 id="إنشاء-معرض-فني-art-gallery">
		إنشاء معرض فني Art Gallery
	</h2>

	<p>
		حان الوقت الآن لإنشاء معرض صور واستخدام الأدوات التي تعلمناها في التعامل مع الصور في canvas سيكون المعرض عبارة عن جدول يحوي مجموعة صور. 
	</p>

	<p>
		عند تحميل الصفحة يقوم العنصر canvas بإدراج الصور ورسم إطار حول كل صورة.  في حالتنا هذه سيكون لكل صورة طول وعرض ثابتين وكذلك الإطار. 
	</p>

	<p>
		سنقوم باسترداد صورة الإطار من الرابط: 
	</p>

	<p style="text-align: center;">
		<a href="https://mdn.mozillademos.org/files/242/Canvas_picture_frame.png" rel="external nofollow">https://mdn.mozillademos.org/files/242/Canvas_picture_frame.png</a>
	</p>

	<p style="text-align: center;">
		<img alt="Canvas_picture_frame.png" class="ipsImage ipsImage_thumbnailed" data-fileid="13484" data-unique="955f950ai" src="https://academy.hsoub.com/uploads/monthly_2016_02/Canvas_picture_frame.png.d740cbfa79a3b2e69dc96aee042c3c54.png"></p>

	<p>
		ثم إنشاء حلقة تكرار للإنشاء رقعة canvas لكل صورة ومن ثم رسم الصورة ويتم ذلك باستخدام الدالة:
	</p>
</div>

<div id="wmd-preview-section-28">
	<pre class="ipsCode prettyprint lang-html prettyprinted" id="ips_uid_8392_7">
<span class="pln">parentNode.insertBefore</span></pre>

	<p>
		تقوم هذه الدالة بإدراج الصورة قبل إدراج عنصر canvas في عناصر DOM:
	</p>
</div>

<div id="wmd-preview-section-29">
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8392_9">
<span class="pln"> </span><span class="com">// Insert before the image</span><span class="pln">
      document</span><span class="pun">.</span><span class="pln">images</span><span class="pun">.</span><span class="pln">parentNode</span><span class="pun">.</span><span class="pln">insertBefore</span><span class="pun">(</span><span class="pln">canvas</span><span class="pun">,</span><span class="pln">document</span><span class="pun">.</span><span class="pln">images</span><span class="pun">);</span></pre>

	<p>
		بعد إنشاء عنصر canvas وإدراج الصورة نقوم باستخدام سياق التصيير واستدعاء الدالة<span style="font-family:courier new,courier,monospace;"> ()drawImage</span> لرسم الصورة على الرقعة:
	</p>

	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_8392_11">
<span class="pln">ctx</span><span class="pun">.</span><span class="pln">drawImage</span><span class="pun">(</span><span class="pln">document</span><span class="pun">.</span><span class="pln">images</span><span class="pun">,</span><span class="lit">15</span><span class="pun">,</span><span class="lit">20</span><span class="pun">);</span></pre>

	<p>
		إضافة بعض التنسيقات CSS:
	</p>
</div>

<div id="wmd-preview-section-31">
	<pre class="ipsCode prettyprint lang-css prettyprinted" id="ips_uid_5464_15">
<span class="pln">body </span><span class="pun">{</span><span class="pln"> 
  background</span><span class="pun">:</span><span class="pln"> </span><span class="pln"> </span><span class="pun">-</span><span class="lit">100px</span><span class="pln"> repeat</span><span class="pun">-</span><span class="pln">x url</span><span class="pun">(</span><span class="pln">https</span><span class="pun">:</span><span class="com">//mdn.mozillademos.org/files/5415/bg_gallery.png) #4F191A; </span><span class="pln">
  margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">10px</span><span class="pun">;</span><span class="pln"> 
</span><span class="pun">}</span><span class="pln">

img </span><span class="pun">{</span><span class="pln"> 
  display</span><span class="pun">:</span><span class="pln"> none</span><span class="pun">;</span><span class="pln"> 
</span><span class="pun">}</span><span class="pln">

table </span><span class="pun">{</span><span class="pln"> 
  margin</span><span class="pun">:</span><span class="pln"> </span><span class="pln"> </span><span class="kwd">auto</span><span class="pun">;</span><span class="pln"> 
</span><span class="pun">}</span><span class="pln">

td </span><span class="pun">{</span><span class="pln"> 
  padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">15px</span><span class="pun">;</span><span class="pln"> 
</span><span class="pun">}</span></pre>

	<p>
		السكربت أدناه يقوم برسم الصور مع الإطار:
	</p>
</div>

<div id="wmd-preview-section-32">
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5464_17">
<span class="kwd">function</span><span class="pln"> draw</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">

  </span><span class="com">// Loop through all images</span><span class="pln">
  </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">var</span><span class="pln"> i</span><span class="pun">=</span><span class="pun">;</span><span class="pln">i</span><span class="pun">&lt;</span><span class="pln">document</span><span class="pun">.</span><span class="pln">images</span><span class="pun">.</span><span class="pln">length</span><span class="pun">;</span><span class="pln">i</span><span class="pun">++){</span><span class="pln">

    </span><span class="com">// Don't add a canvas for the frame image</span><span class="pln">
    </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">document</span><span class="pun">.</span><span class="pln">images</span><span class="pun">[</span><span class="pln">i</span><span class="pun">].</span><span class="pln">getAttribute</span><span class="pun">(</span><span class="str">'id'</span><span class="pun">)!=</span><span class="str">'frame'</span><span class="pun">){</span><span class="pln">

      </span><span class="com">// Create canvas element</span><span class="pln">
      canvas </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="str">'canvas'</span><span class="pun">);</span><span class="pln">
      canvas</span><span class="pun">.</span><span class="pln">setAttribute</span><span class="pun">(</span><span class="str">'width'</span><span class="pun">,</span><span class="lit">132</span><span class="pun">);</span><span class="pln">
      canvas</span><span class="pun">.</span><span class="pln">setAttribute</span><span class="pun">(</span><span class="str">'height'</span><span class="pun">,</span><span class="lit">150</span><span class="pun">);</span><span class="pln">

      </span><span class="com">// Insert before the image</span><span class="pln">
      document</span><span class="pun">.</span><span class="pln">images</span><span class="pun">[</span><span class="pln">i</span><span class="pun">].</span><span class="pln">parentNode</span><span class="pun">.</span><span class="pln">insertBefore</span><span class="pun">(</span><span class="pln">canvas</span><span class="pun">,</span><span class="pln">document</span><span class="pun">.</span><span class="pln">images</span><span class="pun">[</span><span class="pln">i</span><span class="pun">]);</span><span class="pln">

      ctx </span><span class="pun">=</span><span class="pln"> canvas</span><span class="pun">.</span><span class="pln">getContext</span><span class="pun">(</span><span class="str">'2d'</span><span class="pun">);</span><span class="pln">

      </span><span class="com">// Draw image to canvas</span><span class="pln">
      ctx</span><span class="pun">.</span><span class="pln">drawImage</span><span class="pun">(</span><span class="pln">document</span><span class="pun">.</span><span class="pln">images</span><span class="pun">[</span><span class="pln">i</span><span class="pun">],</span><span class="lit">15</span><span class="pun">,</span><span class="lit">20</span><span class="pun">);</span><span class="pln">

      </span><span class="com">// Add frame</span><span class="pln">
      ctx</span><span class="pun">.</span><span class="pln">drawImage</span><span class="pun">(</span><span class="pln">document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'frame'</span><span class="pun">),</span><span class="pun">,</span><span class="pun">);</span><span class="pln">
    </span><span class="pun">}</span><span class="pln">
  </span><span class="pun">}</span><span class="pln">
</span><span class="pun">}</span></pre>

	<p>
		ستظهر الصورة على الشكل التالي:
	</p>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2016_02/56cca3da8644b_6.png.592370f5e400be1e02a161c2512fd0a6.png" data-fileid="13474" rel="external"><img alt="­í©¡6.png" class="ipsImage ipsImage_thumbnailed" data-fileid="13474" data-unique="jx3n2n988" src="https://academy.hsoub.com/uploads/monthly_2016_02/56cca3dbd2d48_6.thumb.png.2b7fe9efedb28cad5fe3954a8f4750dc.png"></a>
	</p>

	<p>
		استعراض المثال على <a href="https://jsfiddle.net/1gurhucu/" rel="external nofollow">jsfiddle</a>.
	</p>
</div>

<div id="wmd-preview-section-33">
	<h2 id="التحكم-بسلوك-التحجيم-scaling-behavior">
		التحكم بسلوك التحجيم Scaling Behavior
	</h2>

	<p>
		كما ذكرت سابقًا أن عملية تحجيم الصورة يمكن أن تؤدي إلى تشويهها أو جعلها تبدو غير واضحة. يمكنك استخدام  الخاصية <span style="font-family:courier new,courier,monospace;">imageSmoothingEnabled</span> للتحكم باستخدام خوارزمية تنعيم أو تمهيد الصورة Smoothing وذلك بتحديد القيمة التي تأخذها إما true أو false
	</p>
</div>

<div id="wmd-preview-section-34">
	<pre class="ipsCode prettyprint lang-javascript prettyprinted" id="ips_uid_5464_19">
<span class="pln">ctx</span><span class="pun">.</span><span class="pln">mozImageSmoothingEnabled </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
ctx</span><span class="pun">.</span><span class="pln">webkitImageSmoothingEnabled </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
ctx</span><span class="pun">.</span><span class="pln">msImageSmoothingEnabled </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
ctx</span><span class="pun">.</span><span class="pln">imageSmoothingEnabled </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span></pre>

	<h2>
		التحولات Transformations
	</h2>
</div>

<div id="wmd-preview-section-35">
	<p>
		يوفّر سياق التصيير Rendering Context في canvas مجموعة من الدوال لتطبيق التحولات على الأشكال في canvas كالتحريك، النقل، الدوران والتحجيم حيث يمكنك تطبيق هذه الخصائص بطرق مختلفة على الأشكال البسيطة في الرقعة canvas والحصول على أشكال معقدة أو متحركة بكل سهولة. <br>
		قبل البدء بالتعرّف على دوال التحولات التي يوفرها سياق التصيير دعونا نلقي نظرة على حالتين لا غنى عنهما سنستخدمهما بمجرد البدء بتوليد أشكال معقدة باستخدام خصائص التحويل في canvas.
	</p>

	<h3>
		حالتي الحفظ والاستعادة Saving and restoring state
	</h3>

	<ul>
<li>
			<span style="font-family:courier new,courier,monospace;">()save</span>: تقوم هذه الدالة بحفظ الحالة التي تكون عليها الرقعة في الوقت الحالي.
		</li>
		<li>
			<span style="font-family:courier new,courier,monospace;">()restore</span>: تعيد هذه الدالة أحدث حالة كانت عليها الرقعة canvas.
		</li>
	</ul>
<p>
		يتم تخزين حالات الرقعة في الـ stack أو المجمع حيث أنه في كل مرة يتم فيها استدعاء الدالة <span style="font-family:courier new,courier,monospace;">()save </span>يتم وضع حالة الرسم الحالية في المجمع.
	</p>

	<p>
		مم تتكون حالة الرسم؟
	</p>

	<p>
		تتكون حالة الرسم من العناصر التالية: 
	</p>

	<ul>
<li>
			التحولات التي يمكن تطبيقها في سياق التصيير كالنقل translate، الدوران rotate والتحجيم scale. 
		</li>
		<li>
			القيم الحالية للخصائص التالية:
			<ul>
<li>
					<span style="font-family:courier new,courier,monospace;">strokeStyle,  fillStyle</span>
				</li>
				<li>
					<span style="font-family:courier new,courier,monospace;">globalAlpha</span>
				</li>
				<li>
					<span style="font-family:courier new,courier,monospace;">lineWidth,  lineCap,  lineJoin</span>
				</li>
				<li>
					<span style="font-family:courier new,courier,monospace;">miterLimit</span>
				</li>
				<li>
					<span style="font-family:courier new,courier,monospace;">lineDashOffset</span>
				</li>
				<li>
					<span style="font-family:courier new,courier,monospace;">shadowOffsetX, shadowOffsetY</span>
				</li>
				<li>
					<span style="font-family:courier new,courier,monospace;">shadowBlur, shadowColor</span>
				</li>
				<li>
					<span style="font-family:courier new,courier,monospace;">globalCompositeOperation</span>
				</li>
				<li>
					<span style="font-family:courier new,courier,monospace;">font, textAlign, textBaseline</span>
				</li>
				<li>
					<span style="font-family:courier new,courier,monospace;">direction</span>
				</li>
				<li>
					<span style="font-family:courier new,courier,monospace;">imageSmoothingEnabled</span>
				</li>
			</ul>
</li>
	</ul>
</div>

<div id="wmd-preview-section-36">
	<ul>
<li>
			مسار clipping path الحالي.
		</li>
	</ul>
<p>
		<strong>ملاحظة</strong>: يمكنك استدعاء الدالة <span style="font-family:courier new,courier,monospace;">()save</span> عدة مرات كما تريد.
	</p>

	<p>
		في كل مرة يتم فيها استدعاء الدالة<span style="font-family:courier new,courier,monospace;"> ()restore</span> يتم أخذ آخر حالة حفظ موجودة في المجمع واسترجاع جميع الإعدادات الأخيرة المحفوظة.
	</p>

	<p>
		سنكمل في الدرس المقبل شرح دوال التحولات وعرض مثال واضح عن استخدام حالتي الحفظ والاستعادة في سياق التصيير بالإضافة إلى شرح التحولات وطرق التعامل معها مع عرض مثال لكل خاصية تحول لترى كيف يمكنك عمل مجموعة من الأشكال المعقدة وتحريكها على عنصر الرقعة canvas.
	</p>

	<p>
		<a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API" rel="external nofollow">المصادر</a><em><em><em> </em></em></em>
	</p>
</div>
]]></description><guid isPermaLink="false">290</guid><pubDate>Sat, 20 Feb 2016 22:14:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x639;&#x627;&#x645;&#x644; &#x645;&#x639; &#x627;&#x644;&#x639;&#x646;&#x635;&#x631; Canvas &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A; (&#x631;&#x633;&#x645; &#x627;&#x644;&#x635;&#x648;&#x631; )</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%B9%D9%86%D8%B5%D8%B1-canvas-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-%D8%B1%D8%B3%D9%85-%D8%A7%D9%84%D8%B5%D9%88%D8%B1-r257/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2016_01/canvas-javascript-images.png.6be4bc62c3f5e4c97924279cda6a61fa.png" /></p>

<div id="wmd-preview-section-15">
	<div id="wmd-preview-section-37">
		<div id="wmd-preview-section-37">
			<p id="التعامل-مع-canvas-باستخدام-جافا-سكربتالأنماط-الظلال-والنصوص">
				سنتعرف في هذا الدّرس على الأنماط Patterns، الظلال Shadows وقواعد الملء في Canvas بالإضافة لرسم النصوص وتطبيق التنسيقات عليها مثل أنواع الخطوط Fonts وخصائصها. كما سنتعرف على واحدة من السمات الأكثر إثارة في canvas وهي القدرة على استخدام الصور لعمل تركيبات صور ديناميكية، خلفيات أو حتى شخصيات الألعاب.
			</p>

			<p style="text-align: center;">
				<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2016_01/canvas-javascript-images.png.fd0faaea9a17fd697bb4dcb2e832fd55.png"><img alt="canvas-javascript-images.thumb.png.ce295" class="ipsImage ipsImage_thumbnailed" data-fileid="11870" src="https://academy.hsoub.com/uploads/monthly_2016_01/canvas-javascript-images.thumb.png.ce295a1d8806659430543f6569a3f08d.png"></a>
			</p>
		</div>

		<div id="wmd-preview-section-38">
			<h2 id="الأنماط-patterns">
				الأنماط Patterns
			</h2>

			<p>
				تتيح لك canvas إنشاء أنماط باستخدام الصور وتحديد أنواعها باستخدام الدالة <span style="font-family:courier new,courier,monospace;">()createPattern</span>. تأخذ الدالة <span style="font-family:courier new,courier,monospace;">()createPtterns</span> معاملين هما الصورة المراد استخدامها لتطبيق النمط والتي يمكن أن تكون عنصر HTML أو وسم <span style="font-family:courier new,courier,monospace;">&lt;video&gt;</span> أو حتى عنصر canvas آخر. 
			</p>

			<p>
				المعامل الآخر هو النوع Type وهو عبارة عن نص string يحدد كيفيّة استخدام الصورة لتطبيق النمط.
			</p>

			<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4">
<span class="pln">createPattern</span><span class="pun">(</span><span class="pln">image</span><span class="pun">,</span><span class="pln"> type</span><span class="pun">)</span></pre>

			<p>
				يأخذ المعامل <span style="font-family:courier new,courier,monospace;">type</span> أحد القيم التالية والتي تحدد كيفية استخدام الصورة لإنشاء النمط Pattern: 
			</p>

			<ul><li>
					<strong>Repeat</strong>: تكرر الصورة في الاتجاهين الأفقي Horizontal والعمودي Vertical 
				</li>
				<li>
					<strong>repeat-x</strong>: تكرر الصورة في الاتجاه الأفقي Horizontal 
				</li>
				<li>
					<strong>repeat-y</strong>: تكرر الصورة في الاتجاه العمودي Vertical 
				</li>
				<li>
					<strong>no-repeat</strong>: تظهر الصورة مرة واحد كما هي.
				</li>
			</ul><p>
				تشبه الدالة <span style="font-family:courier new,courier,monospace;">()createPattern</span> دوال التدرج اللّوني gradient التي شرحتها في <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%AA%D8%B5%D8%A7%D9%85%D9%8A%D9%85%D8%8C-%D8%A7%D9%84%D8%A3%D9%84%D9%88%D8%A7%D9%86-%D9%88%D8%A7%D9%84%D8%AE%D8%B7%D9%88%D8%B7-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-canvas-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r239/">الدرس السّابق</a>. 
			</p>

			<p>
				عند إنشاء نمط يمكننا إسناده إلى الخاصية <span style="font-family:courier new,courier,monospace;">fillStyle</span> أو <span style="font-family:courier new,courier,monospace;">strokeStyle</span> كما في المثال التالي:
			</p>

			<pre class="html ipsCode prettyprint prettyprinted" data-pbcklang="html" data-pbcktabsize="4">
<span class="kwd">var</span><span class="pln"> img </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Image</span><span class="pun">();</span><span class="pln"> 
img</span><span class="pun">.</span><span class="pln">src </span><span class="pun">=</span><span class="pln"> </span><span class="str">'someimage.png'</span><span class="pun">;</span><span class="pln"> 
</span><span class="kwd">var</span><span class="pln"> ptrn </span><span class="pun">=</span><span class="pln"> ctx</span><span class="pun">.</span><span class="pln">createPattern</span><span class="pun">(</span><span class="pln">img</span><span class="pun">,</span><span class="str">'repeat'</span><span class="pun">);</span></pre>

			<p>
				<strong>ملاحظة</strong>: تأكّد من أنك قمت بإنشاء صورة وإعطائها المسار الصحيح قبل استدعاء الدالة <span style="font-family:courier new,courier,monospace;">()createPattern</span>. في هذا المثال سنقوم بإنشاء نمط وإسناده للخاصية <span style="font-family:courier new,courier,monospace;">fillStyle</span> حيث سننشئ النمط ضمن الدالة <span style="font-family:courier new,courier,monospace;">onload</span> للصورة وذلك للتأكد من تحميل الصورة قبل إسنادها للنمط.
			</p>

			<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4">
<span class="kwd">function</span><span class="pln"> draw</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
  </span><span class="kwd">var</span><span class="pln"> ctx </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'canvas'</span><span class="pun">).</span><span class="pln">getContext</span><span class="pun">(</span><span class="str">'2d'</span><span class="pun">);</span><span class="pln"> 
  </span><span class="kwd">var</span><span class="pln"> img </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Image</span><span class="pun">();</span><span class="pln"> 
  img</span><span class="pun">.</span><span class="pln">src </span><span class="pun">=</span><span class="pln"> </span><span class="str">'https://mdn.mozillademos.org/files/222/Canvas_createpattern.png'</span><span class="pun">;</span><span class="pln"> 
  img</span><span class="pun">.</span><span class="pln">onload </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(){</span><span class="pln"> 
    </span><span class="kwd">var</span><span class="pln"> ptrn </span><span class="pun">=</span><span class="pln"> ctx</span><span class="pun">.</span><span class="pln">createPattern</span><span class="pun">(</span><span class="pln">img</span><span class="pun">,</span><span class="str">'repeat'</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">fillStyle </span><span class="pun">=</span><span class="pln"> ptrn</span><span class="pun">;</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">fillRect</span><span class="pun">(</span><span class="lit">0</span><span class="pun">,</span><span class="lit">0</span><span class="pun">,</span><span class="lit">150</span><span class="pun">,</span><span class="lit">150</span><span class="pun">);</span><span class="pln"> 
  </span><span class="pun">}</span><span class="pln"> 
</span><span class="pun">}</span></pre>

			<p>
				النتيجة:
			</p>

			<p style="text-align: center;">
				<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2016_01/001.png.15198b236efb71db6e86ad4a3ed8ea4e.png"><img alt="001.thumb.png.7def5aaebab487f20c686c7694" class="ipsImage ipsImage_thumbnailed" data-fileid="11865" src="https://academy.hsoub.com/uploads/monthly_2016_01/001.thumb.png.7def5aaebab487f20c686c7694c7f332.png"></a>
			</p>
		</div>

		<div id="wmd-preview-section-41">
			<h2 id="الظلال-shadows">
				الظلال Shadows
			</h2>

			<p>
				باستخدام الظلال في canvas يمكنك عمل تظليل للنصوص والصور. استخدام الظلال في canvas يتضمن 4 خصائص:
			</p>

			<ul><li>
					<strong>shadowOffsetX = float</strong>
				</li>
			</ul><p>
				تشير إلى أن الظل يمتد من الكائن بمسافة أفقية. لا تتأثر هذه القيمة بمصفوفة التحويل <a href="https://en.wikipedia.org/wiki/Transformation_matrix" rel="external nofollow">Transformation matrix</a> وقيمتها الافتراضية هي 0. 
			</p>

			<ul><li>
					<strong>shadowOffsetY = float</strong>
				</li>
			</ul><p>
				تشير إلى أن الظل يمتد من الكائن بمسافة عمودية. لا تتأثر هذه القيمة بمصفوفة التحويل <a href="https://en.wikipedia.org/wiki/Transformation_matrix" rel="external nofollow">Transformation matrix</a> وقيمتها الافتراضية هي 0. 
			</p>

			<ul><li>
					<strong>shadowBlur = float</strong>
				</li>
			</ul><p>
				تحدد حجم تأثير الضبابية blurring. لا تتعلق هذه القيمة بعدد الـ pixels ولا تتأثر بمصفوفة التحويل <a href="https://en.wikipedia.org/wiki/Transformation_matrix" rel="external nofollow">Transformation matrix</a> وقيمتها الافتراضية هي 0. 
			</p>

			<ul><li>
					<strong>shadowColor = color</strong>
				</li>
			</ul><p>
				هي قيمة ألوان CSS قياسية وتحدد لون الظل وقيمتها الافتراضية هي لون أسود بشفافية كاملة.
			</p>

			<p>
				الخاصيتان<span style="font-family:courier new,courier,monospace;"> shadowOffsetX</span> و <span style="font-family:courier new,courier,monospace;">shadowOffsetY</span> تشيران إلى أي مدى ينبغي أن يمتد الظل من الكائن في الاتجاه X والاتجاه Y. تأخذ الخاصيتين قيمًا سالبة وذلك لتحديد اتجاه الظل إما لليسار <span style="font-family:courier new,courier,monospace;">X-</span> أو للأعلى <span style="font-family:courier new,courier,monospace;">Y-</span>.
			</p>

			<p>
				الخاصية <span style="font-family:courier new,courier,monospace;">shadowBlur</span> تحدد حجم الضبابية للظل ولا تتعلق بعدد الـ pixels ولا تتأثر بمصفوفة التحويل Transformation matrix وقيمتها الافتراضية هي 0. 
			</p>

			<p>
				المثال التالي يرسم نصًا بتأثيرات ظلال مختلفة باستخدام القيم أعلاه:
			</p>

			<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4">
<span class="kwd">function</span><span class="pln"> draw</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
  </span><span class="kwd">var</span><span class="pln"> ctx </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'canvas'</span><span class="pun">).</span><span class="pln">getContext</span><span class="pun">(</span><span class="str">'2d'</span><span class="pun">);</span><span class="pln"> 

  ctx</span><span class="pun">.</span><span class="pln">shadowOffsetX </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln"> 
  ctx</span><span class="pun">.</span><span class="pln">shadowOffsetY </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln"> 
  ctx</span><span class="pun">.</span><span class="pln">shadowBlur </span><span class="pun">=</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln"> 
  ctx</span><span class="pun">.</span><span class="pln">shadowColor </span><span class="pun">=</span><span class="pln"> </span><span class="str">"rgba(0, 0, 0, 0.5)"</span><span class="pun">;</span><span class="pln"> 
  ctx</span><span class="pun">.</span><span class="pln">font </span><span class="pun">=</span><span class="pln"> </span><span class="str">"20px Times New Roman"</span><span class="pun">;</span><span class="pln"> 
  ctx</span><span class="pun">.</span><span class="pln">fillStyle </span><span class="pun">=</span><span class="pln"> </span><span class="str">"Black"</span><span class="pun">;</span><span class="pln"> 
  ctx</span><span class="pun">.</span><span class="pln">fillText</span><span class="pun">(</span><span class="str">"أهلًا بك في أكاديمية حسوب"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">30</span><span class="pun">);</span><span class="pln"> 
</span><span class="pun">}</span></pre>
		</div>

		<div id="wmd-preview-section-43">
			<p style="text-align: center;">
				<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2016_01/002.png.b52d1a2fc14794234067c29196086bc0.png"><img alt="002.thumb.png.6ab7659bf82bbdabe9275689dc" class="ipsImage ipsImage_thumbnailed" data-fileid="11866" src="https://academy.hsoub.com/uploads/monthly_2016_01/002.thumb.png.6ab7659bf82bbdabe9275689dc1fc49f.png"></a>
			</p>

			<h2 id="قواعد-الملء-fill-rules">
				قواعد الملء Fill Rules
			</h2>

			<p>
				عند استخدام الخاصية <span style="font-family:courier new,courier,monospace;">()fill</span> يمكنك تحديد خوارزمية الملء التي تريد تطبيقها ويمكن من خلالها تحديد فيما إذا كانت النقطة داخل أو خارج المسار وبالتالي تحديد هل سيتم ملئها أم لا. 
			</p>

			<p>
				ويوجد لها قيمتان:
			</p>

			<ul><li>
					nonzero وهي القيمة الافتراضية.
				</li>
				<li>
					evenodd
				</li>
			</ul><p>
				مثال:
			</p>

			<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4">
<span class="kwd">function</span><span class="pln"> draw</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
  </span><span class="kwd">var</span><span class="pln"> ctx </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'canvas'</span><span class="pun">).</span><span class="pln">getContext</span><span class="pun">(</span><span class="str">'2d'</span><span class="pun">);</span><span class="pln"> 
  
  ctx</span><span class="pun">.</span><span class="pln">beginPath</span><span class="pun">();</span><span class="pln"> 
  ctx</span><span class="pun">.</span><span class="pln">arc</span><span class="pun">(</span><span class="lit">50</span><span class="pun">,</span><span class="pln"> </span><span class="lit">50</span><span class="pun">,</span><span class="pln"> </span><span class="lit">30</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">PI</span><span class="pun">*</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">);</span><span class="pln"> 
  ctx</span><span class="pun">.</span><span class="pln">arc</span><span class="pun">(</span><span class="lit">50</span><span class="pun">,</span><span class="pln"> </span><span class="lit">50</span><span class="pun">,</span><span class="pln"> </span><span class="lit">15</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">PI</span><span class="pun">*</span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">);</span><span class="pln"> 
  ctx</span><span class="pun">.</span><span class="pln">fill</span><span class="pun">(</span><span class="str">"evenodd"</span><span class="pun">);</span><span class="pln"> 
</span><span class="pun">}</span></pre>

			<p style="text-align: center;">
				<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2016_01/003.png.6ddeb699aabfc15b4afac79a77406c45.png"><img alt="003.thumb.png.5c4196a7958e98c911fc2b1447" class="ipsImage ipsImage_thumbnailed" data-fileid="11867" src="https://academy.hsoub.com/uploads/monthly_2016_01/003.thumb.png.5c4196a7958e98c911fc2b14475df48b.png"></a>
			</p>
		</div>

		<div id="wmd-preview-section-45">
			<h2 id="رسم-النصوص">
				رسم النصوص
			</h2>

			<p>
				كأي شكل من الأشكال التي يمكن رسمها على canvas يمكن أيضًا رسم النصوص وتطبيق خصائص مختلفة عليها.
			</p>

			<p>
				يوفّر سياق التصيير rendering context في canvas طريقتين لتصيير النصوص:
			</p>

			<h3>
				1- باستخدام الدالة <span style="font-family:courier new,courier,monospace;">fillText</span>
			</h3>

			<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4">
<span class="pln">fillText</span><span class="pun">(</span><span class="pln">text</span><span class="pun">,</span><span class="pln"> x</span><span class="pun">,</span><span class="pln"> y </span><span class="pun">[,</span><span class="pln"> maxWidth</span><span class="pun">])</span></pre>

			<p>
				تملأ نصًا مُعيّنًا عند موضع x,y معين، المعامل <span style="font-family:courier new,courier,monospace;">maxWidth</span> معامل اختياري يحدد أقصى عرض للرسم.
			</p>

			<h3>
				2- باستخدام الدالة <span style="font-family:courier new,courier,monospace;">strokeText</span>
			</h3>

			<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4">
<span class="pln"> strokeText</span><span class="pun">(</span><span class="pln">text</span><span class="pun">,</span><span class="pln"> x</span><span class="pun">,</span><span class="pln"> y </span><span class="pun">[,</span><span class="pln"> maxWidth</span><span class="pun">])</span></pre>

			<p>
				تملأ حواف نص معين عند موضع x,y معين، المعامل <span style="font-family:courier new,courier,monospace;">maxWidth</span> معامل اختياري يحدد أقصى عرض للرسم. 
			</p>

			<p>
				<strong>مثال: </strong>ملء نص باستخدام <span style="font-family:courier new,courier,monospace;">fillStyle</span>
			</p>

			<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4">
<span class="kwd">function</span><span class="pln"> draw</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
  </span><span class="kwd">var</span><span class="pln"> ctx </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'canvas'</span><span class="pun">).</span><span class="pln">getContext</span><span class="pun">(</span><span class="str">'2d'</span><span class="pun">);</span><span class="pln"> 

  ctx</span><span class="pun">.</span><span class="pln">font </span><span class="pun">=</span><span class="pln"> </span><span class="str">"48px serif"</span><span class="pun">;</span><span class="pln"> 
  ctx</span><span class="pun">.</span><span class="pln">fillText</span><span class="pun">(</span><span class="str">"Hello world"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">,</span><span class="pln"> </span><span class="lit">50</span><span class="pun">);</span><span class="pln"> 
</span><span class="pun">}</span></pre>

			<p style="text-align: center;">
				<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2016_01/004.png.fb1fd585a432192b6c3ae0e461d74076.png"><img alt="004.thumb.png.bd416efe0998c6cffe53eb5c2d" class="ipsImage ipsImage_thumbnailed" data-fileid="11868" src="https://academy.hsoub.com/uploads/monthly_2016_01/004.thumb.png.bd416efe0998c6cffe53eb5c2d72235f.png"></a>
			</p>
		</div>

		<div id="wmd-preview-section-46">
			<p>
				<strong>مثال: </strong>ملء حواف نص باستخدام <span style="font-family:courier new,courier,monospace;">strokeStyle</span>
			</p>

			<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4">
<span class="kwd">function</span><span class="pln"> draw</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
  </span><span class="kwd">var</span><span class="pln"> ctx </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'canvas'</span><span class="pun">).</span><span class="pln">getContext</span><span class="pun">(</span><span class="str">'2d'</span><span class="pun">);</span><span class="pln"> 

  ctx</span><span class="pun">.</span><span class="pln">font </span><span class="pun">=</span><span class="pln"> </span><span class="str">"48px serif"</span><span class="pun">;</span><span class="pln"> 
  ctx</span><span class="pun">.</span><span class="pln">strokeText</span><span class="pun">(</span><span class="str">"Hello world"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">,</span><span class="pln"> </span><span class="lit">50</span><span class="pun">);</span><span class="pln"> 
</span><span class="pun">}</span></pre>

			<p style="text-align: center;">
				<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2016_01/005.png.7a49741dbf3db02da51335187f7fddb4.png"><img alt="005.thumb.png.2c0ccdd34d1d82097d6e496618" class="ipsImage ipsImage_thumbnailed" data-fileid="11869" src="https://academy.hsoub.com/uploads/monthly_2016_01/005.thumb.png.2c0ccdd34d1d82097d6e496618ce3fce.png"></a>
			</p>
		</div>

		<div id="wmd-preview-section-48">
			<h2 id="تصميم-وتنسيق-النصوص">
				تصميم وتنسيق النصوص
			</h2>

			<p>
				يوفر سياق التصيير Rendering Context مجموعة من الخصائص تمكّنك من تحديد المظهر الذي تريد إظهار النص به على Canvas. ستبدو هذه الخصائص مألوفة لك إن كنت قد عملت على CSS من قبل.
			</p>

			<ul><li>
					<strong>font = value</strong>
				</li>
			</ul><p>
				تحدد نمط النص الحالي (نوع الخط) الذي سيظهر به النص، تستخدم هذه الخاصية نفس قواعد استخدام الخاصية CSS font. القيمة الافتراضية للخط هي 10px sans-serif.
			</p>

			<ul><li>
					<strong>textAlign = value</strong>
				</li>
			</ul><p>
				تُحدّد إعدادات محاذاة النص. القيم التي تأخذها هذه الخاصية هي start ،end ،left ،right أو center. القيمة الافتراضية لها هي center.
			</p>

			<ul><li>
					<strong>textBaseline = value</strong>
				</li>
			</ul><p>
				تُحدّد إعدادات خط الأساس .Baseline القيم التي تأخذها الخاصية text Baseline هي top ،hanging ،middle ،alphabetic ،ideographic أو bottom. القيمة الافتراضية لها هي alphabetic.
			</p>

			<ul><li>
					<strong>direction = value</strong>
				</li>
			</ul><p>
				تُحدّد الاتجاهية. القيم التي تأخذها الخاصية <span style="font-family:courier new,courier,monospace;">textAlign</span> هي ltr ،rtl ،inherit. القيمة الافتراضية لها هي inherit.
			</p>

			<p>
				يوضّح الرّسم البياني التالي المأخوذ من WHATWG مختلف خطوط الأساس Baseline التي تدعمها الخاصية <span style="font-family:courier new,courier,monospace;">textBaseline</span>.
			</p>

			<p>
				مثال:
			</p>

			<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4">
<span class="pln">ctx</span><span class="pun">.</span><span class="pln">font </span><span class="pun">=</span><span class="pln"> </span><span class="str">"48px serif"</span><span class="pun">;</span><span class="pln"> 
ctx</span><span class="pun">.</span><span class="pln">textBaseline </span><span class="pun">=</span><span class="pln"> </span><span class="str">"hanging"</span><span class="pun">;</span><span class="pln"> 
ctx</span><span class="pun">.</span><span class="pln">strokeText</span><span class="pun">(</span><span class="str">"Hello world"</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="lit">100</span><span class="pun">);</span></pre>
		</div>

		<div id="wmd-preview-section-50">
			<h2 id="قياسات-النصوص-المتقدمة">
				قياسات النصوص المتقدمة
			</h2>

			<p>
				في حال كنت بحاجة لتطبيق المزيد من التفاصيل على النصوص فإن الدالة <span style="font-family:courier new,courier,monospace;">()measureText</span> توفر لك إمكانية لقياس النصوص حيث تُرجع الدالة <span style="font-family:courier new,courier,monospace;">()measureText</span> كائن من نوع <span style="font-family:courier new,courier,monospace;">TextMetrics</span> يحتوي على عرض النص الحالي بالبكسل.
			</p>

			<p>
				يظهر المثال التالي كيف يمكنك قياس الخط والحصول على عرضه:
			</p>

			<pre class="html ipsCode prettyprint prettyprinted" data-pbcklang="html" data-pbcktabsize="4">
<span class="kwd">function</span><span class="pln"> draw</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
  </span><span class="kwd">var</span><span class="pln"> ctx </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'canvas'</span><span class="pun">).</span><span class="pln">getContext</span><span class="pun">(</span><span class="str">'2d'</span><span class="pun">);</span><span class="pln"> 
  </span><span class="kwd">var</span><span class="pln"> text </span><span class="pun">=</span><span class="pln"> ctx</span><span class="pun">.</span><span class="pln">measureText</span><span class="pun">(</span><span class="str">"foo"</span><span class="pun">);</span><span class="pln"> 
  </span><span class="kwd">object</span><span class="pln"> text</span><span class="pun">.</span><span class="pln">width</span><span class="pun">;</span><span class="pln">
</span><span class="pun">}</span></pre>
		</div>

		<div id="wmd-preview-section-52">
			<h2 id="الصور">
				الصور
			</h2>

			<p>
				يعتمد استيراد الصور في Canvas على خطوتين أساسيتين: 
			</p>

			<ol><li>
					الحصول على مرجع reference لكائن <span style="font-family:courier new,courier,monospace;">HTMLImage</span> أو لعنصر <span style="font-family:courier new,courier,monospace;">Canvas</span> آخر لاستخدامه كمصدر. يمكن استخدام الصور أيضًا عن طريق توفير رابط URL. 
				</li>
				<li>
					رسم الصورة على canvas باستخدام <span style="font-family:courier new,courier,monospace;">DrawImage</span>. 
				</li>
			</ol><p>
				يستخدم Canvas <abbr title="واجهة برمجية | Application Programming Interface">API</abbr> أي من أنواع البيانات التالية باعتبارها مصدر صورة للحصول على الصور ورسمها: 
			</p>

			<ul><li>
					<span style="font-family:courier new,courier,monospace;">HTMLImageElement</span>: يتم إنشاء الصور باستخدام المنشئ constructor كأي عنصر <span style="font-family:courier new,courier,monospace;">&lt;img&gt;</span> في HTML.
				</li>
				<li>
					<span style="font-family:courier new,courier,monospace;">HTMLVideoElement</span>: استخدام عنصر <span style="font-family:courier new,courier,monospace;">&lt;video&gt;</span> كمصدر للصورة أي استخدام الاطار الحالي للفيديو كصورة.
				</li>
				<li>
					<span style="font-family:courier new,courier,monospace;">HTMLCanvasElement</span>: يمكن استخدام عنصر <span style="font-family:courier new,courier,monospace;">&lt;canvas&gt;</span> آخر كمصدر صورة.
				</li>
			</ul></div>

		<div id="wmd-preview-section-53">
			<h2 id="استخدام-الصور-في-canvas">
				استخدام الصور في Canvas
			</h2>

			<p>
				يوجد عدة طرق لاستخدام الصور في Canvas:
			</p>

			<h3>
				استخدام صور من نفس الصفحة
			</h3>

			<p>
				يمكننا الحصول على مرجع للصور <span style="font-family:courier new,courier,monospace;">reference</span> من نفس الصفحة باستخدام أحد الطرق التالية: 
			</p>

			<ul><li>
					<span style="font-family:courier new,courier,monospace;">document.images collection </span>
				</li>
				<li>
					استخدام الدالة <span style="font-family:courier new,courier,monospace;">()document.getElementsByTagName</span>
				</li>
				<li>
					استخدام الدالة <span style="font-family:courier new,courier,monospace;">()document.getElementById</span> عن طريق معرّف ID الخاص بالصورة
				</li>
			</ul><h3>
				استخدام صور من مجالات أخرى
			</h3>

			<p>
				ويتم ذلك باستخدام الخاصية <span style="font-family:courier new,courier,monospace;">crossorigin</span> للعنصر &lt;img&gt; يمكنك طلب إذن لتحميل الصورة من مجال Domain آخر لاستخدامها في استدعائك للدالة <span style="font-family:courier new,courier,monospace;">()drawImage</span>. إذا سمح مجال الاستضافة وصول cross-domain للصورة فسيتم استخدام الصورة في Canvas دون التأثير عليها أما في حال لم يتم السماح بالوصول للصورة فسيحدث تشويه للعنصر canvas.
			</p>

			<h3>
				استخدام عناصر Canvas أخرى
			</h3>

			<p>
				كما هو الحال مع الصور العادية يمكن الوصول لعناصر canvas أخرى باستخدام الدالة <span style="font-family:courier new,courier,monospace;">()document.getElementsByTagName</span> أو  (<span style="font-family:courier new,courier,monospace;">)document.getElementById.</span>
			</p>

			<p>
				يجب التأكد قبل استخدام عنصر Canvas آخر من أن العنصر الأساسي يحوي على رسم أو مسار. واحدة من أهم استخدامات هذا الأسلوب هو استخدام عنصر canvas كمعرض صور مصغرات لعنصر Canvas أكبر منه.
			</p>

			<h3>
				إنشاء صورة من الصفر
			</h3>

			<p>
				خيار آخر لإنشاء<span style="font-family:courier new,courier,monospace;"> HTMLImageElement</span> هي باستخدام المنشئ<span style="font-family:courier new,courier,monospace;">() Image:</span>
			</p>

			<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4">
<span class="kwd">var</span><span class="pln"> img </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Image</span><span class="pun">();</span><span class="pln"> 
img</span><span class="pun">.</span><span class="pln">src </span><span class="pun">=</span><span class="pln"> </span><span class="str">'myImage.png'</span><span class="pun">;</span></pre>

			<p>
				في حال استدعائك للدالة <span style="font-family:courier new,courier,monospace;">()drawImage</span> قبل الانتهاء من تحميل الصورة قد يظهر خطأ في المتصفحات القديمة لذا عليك التأكد من استخدام الحدث <span style="font-family:courier new,courier,monospace;">load</span> بعد الانتهاء من تحميل الصورة:
			</p>
		</div>

		<div id="wmd-preview-section-54">
			<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4">
<span class="kwd">var</span><span class="pln"> img </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">new</span><span class="pln"> </span><span class="typ">Image</span><span class="pun">();</span><span class="pln"> 
img</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"load"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
  </span><span class="com">// execute drawImage statements here </span><span class="pln">
</span><span class="pun">},</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">);</span><span class="pln"> 
img</span><span class="pun">.</span><span class="pln">src </span><span class="pun">=</span><span class="pln"> </span><span class="str">'myImage.png'</span><span class="pun">;</span></pre>
		</div>

		<div id="wmd-preview-section-55">
			<h3>
				استخدام إطارات الفيديو
			</h3>

			<p>
				يمكنك أيضًا استخدام إطارات الفيديو <span style="font-family:courier new,courier,monospace;">&lt;video&gt;</span> لإظهاره في الـ canvas. مثال:
			</p>

			<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4">
<span class="kwd">function</span><span class="pln"> getMyVideo</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
  </span><span class="kwd">var</span><span class="pln"> canvas </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'canvas'</span><span class="pun">);</span><span class="pln"> 
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">canvas</span><span class="pun">.</span><span class="pln">getContext</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
    </span><span class="kwd">var</span><span class="pln"> ctx </span><span class="pun">=</span><span class="pln"> canvas</span><span class="pun">.</span><span class="pln">getContext</span><span class="pun">(</span><span class="str">'2d'</span><span class="pun">);</span><span class="pln"> 
    </span><span class="kwd">return</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'myvideo'</span><span class="pun">);</span><span class="pln"> 
  </span><span class="pun">}</span><span class="pln"> 
</span><span class="pun">}</span></pre>

			<p>
				سنكمل في الدّرس القادم <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%B9%D9%86%D8%B5%D8%B1-canvas-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-%D8%A7%D9%84%D8%AA%D8%B9%D8%AF%D9%8A%D9%84-%D8%B9%D9%84%D9%89-%D8%A7%D9%84%D8%B5%D9%88%D8%B1-r290/">التعامل مع الصور في canvas</a> والتعرّف على خصائصها بالإضافة لإنشاء معرض فني.
			</p>
		</div>

		<div id="wmd-preview-section-56">
			<p>
				<a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API" rel="external nofollow">المصادر</a>
			</p>
		</div>
	</div>
</div>

<p>
	 
</p>
]]></description><guid isPermaLink="false">257</guid><pubDate>Tue, 26 Jan 2016 18:04:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x639;&#x627;&#x645;&#x644; &#x645;&#x639; &#x627;&#x644;&#x62A;&#x635;&#x627;&#x645;&#x64A;&#x645;&#x60C; &#x627;&#x644;&#x623;&#x644;&#x648;&#x627;&#x646; &#x648;&#x627;&#x644;&#x62E;&#x637;&#x648;&#x637; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; Canvas &#x641;&#x64A; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%AA%D8%B5%D8%A7%D9%85%D9%8A%D9%85%D8%8C-%D8%A7%D9%84%D8%A3%D9%84%D9%88%D8%A7%D9%86-%D9%88%D8%A7%D9%84%D8%AE%D8%B7%D9%88%D8%B7-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-canvas-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r239/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2016_01/canvas-javacript-3.png.fdd640bba1aa5feb31ac4b1644f36003.png" /></p>

<div id="wmd-preview-section-8">
	<p>
		قبل التعرف على التنسيقات والألوان في Canvas سنقوم بتطبيق مثال رسومي للعبة شهيرة باستخدام أنواع المسارات التي تعلّمناها في <a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%B9%D9%86%D8%B5%D8%B1-canvas-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-%D8%B1%D8%B3%D9%85-%D8%A7%D9%84%D8%A3%D8%B4%D9%83%D8%A7%D9%84-r209/">الدرس السابق</a> لإنشاء شخصيات لعبة Pacman الشهيرة.
	</p>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2016_01/5694196a2f23c__1.gif.64339736db8a7d60f4a7d79b09e6b707.gif"><img alt="5694196a31d9b__1.thumb.gif.ecb6b091093a2" class="ipsImage ipsImage_thumbnailed" data-fileid="11010" src="https://academy.hsoub.com/uploads/monthly_2016_01/5694196a31d9b__1.thumb.gif.ecb6b091093a28b4f67ce5136f6368c0.gif"></a>
	</p>
</div>

<div id="wmd-preview-section-9">
	<h2 id="تصميم-واجهة-اللعبة">
		تصميم واجهة اللعبة
	</h2>

	<p>
		سنحتاج لرسم مستطيلات بحواف دائرية لتمثيل الحواجز في اللُّعبة لذا سننشئ دالة ولتكن <span style="font-family:courier new,courier,monospace;">roundRect</span> ونعطيها المعاملات parameters المناسبة لإنشاء مستطيل بحواف دائرية.
	</p>

	<ol><li>
			السّياق Context سنحتاج لتمرير نوع السّياق للدالة التي سيتم إنشاؤها.
		</li>
		<li>
			إحداثيات نقطة بداية الرسم (x,y).
		</li>
		<li>
			عرض المستطيل width.
		</li>
		<li>
			طول المستطيل height.
		</li>
		<li>
			القطر radius.
		</li>
	</ol></div>

<div id="wmd-preview-section-10">
	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
function roundedRect(ctx, x, y, width, height, radius)</pre>

	<p>
		في بداية كل عملية رسم سنحتاج لاستدعاء الدالة <span style="font-family:courier new,courier,monospace;">beginPath</span> لإنشاء القائمة List التي ستحوي نقاط المسار كما شرحنا في الدرس السّابق. <br>
		تتبعها الدالة <span style="font-family:courier new,courier,monospace;">moveTo</span> لتحديد النقطة التي سيبدأ عندها الرسم. سيتم تمرير المعاملات x,y للدالة <span style="font-family:courier new,courier,monospace;">moveTo</span> مع جمع قيمة القطر radius للقيمة y.
	</p>

	<p>
		نبدأ الآن برسم خط مستقيم باستخدام الدالة <span style="font-family:courier new,courier,monospace;">lineTo</span> وتمرير القيمة x نفسها التي بدأنا عندها الرسم مع قيمة y المضاف إليها طول المستطيل height ليتم رسم خط مستقيم بطول المستطيل وطرح قيمة القطر radius وهكذا ينشأ الضلع الأول للمستطيل.
	</p>

	<p>
		الآن رسم حافة المستطيل باستخدام الدالة<span style="font-family:courier new,courier,monospace;"> quadraticCurveTo</span> وتحديد المعاملات:
	</p>

	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
quadraticCurveTo(x, y + height, x + radius, y + height);</pre>

	<p>
		ثم رسم الضلع الثاني للمستطيل باستدعاء الدالة <span style="font-family:courier new,courier,monospace;">lineTo</span>:
	</p>

	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
ctx.lineTo(x + width-radius, y + height);</pre>

	<p>
		رسم الحافة الثانية للمستطيل:
	</p>

	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
ctx.quadraticCurveTo(x + width, y + height, x + width, y + height-radius);</pre>

	<p>
		رسم الضلع الثالثة للمستطيل:
	</p>

	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
ctx.lineTo(x + width, y + radius);</pre>

	<p>
		رسم الحافة الثالثة للمستطيل:
	</p>

	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
ctx.quadraticCurveTo(x + width, y, x + width-radius, y);</pre>

	<p>
		رسم الضلع الرابعة للمستطيل:
	</p>

	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
ctx.lineTo(x + radius, y);</pre>

	<p>
		رسم الحافة الرابعة للمستطيل:
	</p>

	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
ctx.quadraticCurveTo(x, y, x, y + radius);</pre>

	<p>
		أخيرًا استدعاء الدالة <span style="font-family:courier new,courier,monospace;">stroke</span> لرسم المستطيل بشكل مفرغ:
	</p>

	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
function roundedRect(ctx, x, y, width, height, radius){ 
    ctx.beginPath(); 
    ctx.moveTo(x, y + radius); 
    ctx.lineTo(x, y + height-radius); 
    ctx.quadraticCurveTo(x, y + height, x + radius, y + height); 
    ctx.lineTo(x + width-radius, y + height); 
    ctx.quadraticCurveTo(x + width, y + height, x + width, y + height-radius);
    ctx.lineTo(x + width, y + radius); 
    ctx.quadraticCurveTo(x + width, y, x + width-radius, y); 
    ctx.lineTo(x + radius, y); 
    ctx.quadraticCurveTo(x, y, x, y + radius); 
    ctx.stroke(); 
}</pre>

	<p>
		حان الوقت الآن لاستدعاء الدالة <span style="font-family:courier new,courier,monospace;">roundedRect </span>ورسم المستطيلات التي ستمثل الحواجز في لعبة pacman.
	</p>
</div>

<div id="wmd-preview-section-18">
	<p>
		في الدالة <span style="font-family:courier new,courier,monospace;">draw</span> سيتم استدعاء الدالة <span style="font-family:courier new,courier,monospace;">roundedRect</span> على عدد المستطيلات (الحواجز) التي ستكون في الشكل. سأقوم بإنشاء جزء من واجهة اللُّعبة (جزء من الإطار الخارجي وعدد من المستطيلات) كما في الشيفرة التالية:
	</p>

	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
function draw() { 
    var canvas = document.getElementById('tutorial'); 
    if (canvas.getContext) { 
        var ctx = canvas.getContext('2d'); 
        roundedRect(ctx, 12, 12, 150, 150, 15); 
        roundedRect(ctx, 19, 19, 150, 150, 9); 
        roundedRect(ctx, 53, 53, 49, 33, 10); 
        roundedRect(ctx, 53, 119, 49, 16, 6); 
        roundedRect(ctx, 135, 53, 49, 33, 10);  
        roundedRect(ctx, 135, 119, 25, 49, 10); 
    } 
}</pre>

	<p>
		سينتج الشكل:
	</p>
</div>

<div id="wmd-preview-section-19">
	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2016_01/56941aa9cdfda__2.png.86cf9eaa59b6823403c1d23e20e22382.png"><img alt="56941aa9d0069__2.thumb.png.ecba3b7ff1910" class="ipsImage ipsImage_thumbnailed" data-fileid="11011" src="https://academy.hsoub.com/uploads/monthly_2016_01/56941aa9d0069__2.thumb.png.ecba3b7ff19105d27af6a540212a7299.png"></a>
	</p>
</div>

<div id="wmd-preview-section-20">
	<h2 id="رسم-شكل-pac-man">
		رسم شكل pacman
	</h2>

	<p>
		سنحتاج لرسم شكل pac man إلى استدعاء الدالة<span style="font-family:courier new,courier,monospace;"> arc</span> لرسم الشكل الدائري والدالة<span style="font-family:courier new,courier,monospace;"> lineTo</span> لتحديد الفم:
	</p>

	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
ctx.beginPath(); 
ctx.arc(37, 37, 13, Math.PI / 7, -Math.PI / 7, false); 
ctx.lineTo(31, 37); ctx.fill();</pre>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2016_01/56941aaba90bd__3.png.4bb18301d6c3e8167769348aa6df9da8.png"><img alt="56941aabab11e__3.thumb.png.5f48a9689ebc4" class="ipsImage ipsImage_thumbnailed" data-fileid="11012" src="https://academy.hsoub.com/uploads/monthly_2016_01/56941aabab11e__3.thumb.png.5f48a9689ebc47eee8e97d2448330252.png"></a>
	</p>
</div>

<div id="wmd-preview-section-22">
	<h2 id="رسم-مستطيلات-صغيرة-تمثل-طعام-pac-man">
		رسم مستطيلات صغيرة تمثل طعام pacman
	</h2>

	<p>
		سنحتاج إلى حلقات تكرار لإنشاء مستطيلات صغيرة بين الحواجز كما في المثال التالي:
	</p>

	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
for (var i = 0; i &lt; 8; i++) { 
    ctx.fillRect(51 + i * 16, 35, 4, 4); 
} 

for (i = 0; i &lt; 6; i++) { 
    ctx.fillRect(115, 51 + i * 16, 4, 4); 
} 

for (i = 0; i &lt; 8; i++) { 
    ctx.fillRect(51 + i * 16, 99, 4, 4); 
}</pre>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2016_01/56941aac9432d__4.png.7498cbec7d4b8e8fb6b2c8ae5685b25f.png"><img alt="56941aac9634d__4.thumb.png.be96d45ef8ada" class="ipsImage ipsImage_thumbnailed" data-fileid="11013" src="https://academy.hsoub.com/uploads/monthly_2016_01/56941aac9634d__4.thumb.png.be96d45ef8adabdfdc383ffac0f8cd9c.png"></a>
	</p>
</div>

<div id="wmd-preview-section-24">
	<h2 id="رسم-الشبح">
		رسم الشبح
	</h2>

	<p>
		لرسم هيكل جسم الشبح سنستخدم الدالة<span style="font-family:courier new,courier,monospace;"> bezierCurveTo</span> لعمل الشكل العلوي من الجسم ثم استدعاء الدالة <span style="font-family:courier new,courier,monospace;">lineTo</span> بإحداثيات مناسبة لعمل المنحنيات السّفلية للجسم:
	</p>
</div>

<div id="wmd-preview-section-25">
	<h3 id="1-رسم-هيكل-الشبح">
		1- رسم هيكل الشبح
	</h3>
</div>

<div id="wmd-preview-section-26">
	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
ctx.beginPath(); 
ctx.moveTo(83, 116); 
ctx.lineTo(83, 102); 
ctx.bezierCurveTo(83, 94, 89, 88, 97, 88); 
ctx.bezierCurveTo(105, 88, 111, 94, 111, 102); 
ctx.lineTo(111, 116); 
ctx.lineTo(106.333, 111.333); 
ctx.lineTo(101.666, 116); 
ctx.lineTo(97, 111.333); 
ctx.lineTo(92.333, 116); 
ctx.lineTo(87.666, 111.333); 
ctx.lineTo(83, 116); 
ctx.fill();</pre>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2016_01/56941aae22804__5.png.d0c43eec225c7d7026f9b332049a0716.png"><img alt="56941aae24e10__5.thumb.png.7adc66dcc8bc6" class="ipsImage ipsImage_thumbnailed" data-fileid="11014" src="https://academy.hsoub.com/uploads/monthly_2016_01/56941aae24e10__5.thumb.png.7adc66dcc8bc690405486021fe6db11a.png"></a>
	</p>
</div>

<div id="wmd-preview-section-27">
	<h3 id="2-العينان">
		2- العينان
	</h3>
</div>

<div id="wmd-preview-section-28">
	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
ctx.fillStyle = "white"; 
ctx.beginPath(); 
ctx.moveTo(91, 96); 
ctx.bezierCurveTo(88, 96, 87, 99, 87, 101); 
ctx.bezierCurveTo(87, 103, 88, 106, 91, 106); 
ctx.bezierCurveTo(94, 106, 95, 103, 95, 101); 
ctx.bezierCurveTo(95, 99, 94, 96, 91, 96); 
ctx.moveTo(103, 96); 
ctx.bezierCurveTo(100, 96, 99, 99, 99, 101); 
ctx.bezierCurveTo(99, 103, 100, 106, 103, 106); 
ctx.bezierCurveTo(106, 106, 107, 103, 107, 101); 
ctx.bezierCurveTo(107, 99, 106, 96, 103, 96); 
ctx.fill();</pre>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2016_01/56941aaf916ad__6.png.c5fc99eef39d85e8d92d91ceea996246.png"><img alt="56941aaf93c9b__6.thumb.png.3c385e46eaeed" class="ipsImage ipsImage_thumbnailed" data-fileid="11015" src="https://academy.hsoub.com/uploads/monthly_2016_01/56941aaf93c9b__6.thumb.png.3c385e46eaeedeb58b9d60247aa5ab0f.png"></a>
	</p>
</div>

<div id="wmd-preview-section-29">
	<h3 id="3-البؤبؤ-الأيمن">
		3- البؤبؤ الأيمن
	</h3>
</div>

<div id="wmd-preview-section-30">
	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
ctx.fillStyle = "black"; 
ctx.beginPath(); 
ctx.arc(101, 102, 2, 0, Math.PI*2, true); 
ctx.fill();
</pre>
</div>

<div id="wmd-preview-section-31">
	<h3 id="4-البؤبؤ-الأيسر">
		4- البؤبؤ الأيسر
	</h3>
</div>

<div id="wmd-preview-section-32">
	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
ctx.beginPath(); 
ctx.arc(89, 102, 2, 0, Math.PI*2, true); 
ctx.fill();</pre>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2016_01/56941ab712c94__7.png.ca23cb1518a3f5b6a89d1b6e2597da29.png"><img alt="56941ab714da3__7.thumb.png.e83bd891cbb92" class="ipsImage ipsImage_thumbnailed" data-fileid="11016" src="https://academy.hsoub.com/uploads/monthly_2016_01/56941ab714da3__7.thumb.png.e83bd891cbb927fd84da58b711207d44.png"></a>
	</p>

	<p>
		يمكنك استعراض المثال على <a href="https://jsfiddle.net/dgpgqc80/light/" rel="external nofollow">JSFiddle</a>. 
	</p>
</div>

<div id="wmd-preview-section-33">
	<h2 id="الكائن-path2d">
		الكائن Path2D
	</h2>

	<p>
		كما لاحظت في المثال السّابق أن كل شكل هو عبارة عن سلسلة من التعليمات التي تنفذ بالترتيب للحصول على المسار المطلوب ولا يوجد ارتباط واضح بين سلسلة التعليمات والشكل الناتج. ما رأيك أن نقوم بعملية تبسيط وتحسين وذلك بتحديد التعليمات الخاصة بكل شكل عن طريق استخدام الكائن Path2D.
	</p>

	<p>
		يقوم المنشئ Constructor عند إنشاء كائن Path2D بإرجاع كائن Path2D.
	</p>

	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
new Path2D();
new Path2D(path);
new Path2D(d); </pre>

	<p>
		جميع الدوال الخاصة بإنشاء المسارات مثل <span style="font-family:courier new,courier,monospace;">moveTo</span> ،<span style="font-family:courier new,courier,monospace;">rect</span> ،<span style="font-family:courier new,courier,monospace;">arc</span>، أو <span style="font-family:courier new,courier,monospace;">quadraticCurveTo</span>..الخ يمكن استدعاؤها عن طريق الكائن <span style="font-family:courier new,courier,monospace;">Path2D.</span>
	</p>

	<p>
		يوفّر Path2d <abbr title="واجهة برمجية | Application Programming Interface">API</abbr> طريقة للجمع بين المسارات باستخدام الدالة <span style="font-family:courier new,courier,monospace;">addPath</span> ويكون ذلك مفيدًا عندما ترغب في بناء شكل من عدة مكونات.
	</p>
</div>

<div id="wmd-preview-section-34">
	<p>
		سأقوم بإنشاء مستطيل ودائرة باستخدام الكائن <span style="font-family:courier new,courier,monospace;">Path2D.</span> كل من المستطيل والدائرة يُخزن ككائن <span style="font-family:courier new,courier,monospace;">Path2D</span> بحيث تكون متاحة للاستخدام في وقت لاحق.
	</p>

	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
function draw() { 
    var canvas = document.getElementById('canvas'); 
    if (canvas.getContext){ 
        var ctx = canvas.getContext('2d'); 
        var rectangle = new Path2D(); 
        rectangle.rect(10, 10, 50, 50); 
        var circle = new Path2D(); 
        circle.moveTo(125, 35); 
        circle.arc(100, 35, 25, 0, 2 * Math.PI); 
        ctx.stroke(rectangle); 
        ctx.fill(circle); 
    } 
}</pre>

	<p>
		لاحظ أنه تم استدعاء الدالتين <span style="font-family:courier new,courier,monospace;">stroke</span> و <span style="font-family:courier new,courier,monospace;">fill</span> من خلال السّياق <span style="font-family:courier new,courier,monospace;">ctx</span> وتمرير الكائنين <span style="font-family:courier new,courier,monospace;">rectangle</span> و <span style="font-family:courier new,courier,monospace;">circle</span> من نوع <span style="font-family:courier new,courier,monospace;">Path2D</span> كمعاملات. وكذلك أصبح واضحًا ما الشكل الذي ترسمه كل سلسلة من التعليمات. 
	</p>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2016_01/56941ab8ad818__8.png.7764703cd6a67c8281d1a275e2a4a310.png"><img alt="56941ab8af4fd__8.thumb.png.196a36f0e64f0" class="ipsImage ipsImage_thumbnailed" data-fileid="11017" src="https://academy.hsoub.com/uploads/monthly_2016_01/56941ab8af4fd__8.thumb.png.196a36f0e64f02de6bbd230148cc35ba.png"></a>
	</p>
</div>

<div id="wmd-preview-section-36">
	<h2 id="الألوان-colors">
		الألوان Colors
	</h2>

	<p>
		حتى الآن تعرّفنا على الخاصيّة <span style="font-family:courier new,courier,monospace;">fillStyle</span> والتي تقوم بملأ المسار بلون معين. 
	</p>

	<p>
		سنتعرّف أيضًا على الخاصيّة <span style="font-family:courier new,courier,monospace;">fillStroke</span> والتي تقوم بتلوين المسار المفرّغ (تلوين الحواف).
	</p>

	<p>
		إذًا يوجد خاصيتين أساسيتين لتطبيق الألوان على الأشكال: 
	</p>

	<ul><li>
			fillStyle = color 
		</li>
		<li>
			strokeStyle = color
		</li>
	</ul><p>
		القيمة الافتراضية لـ color هي اللون الأسود والتي تمثل القيمة #000000، يمكن تمثيل اللون color بعدة طرق. مثلًا تطبيق اللون البرتقالي باستخدام الخاصيّة <span style="font-family:courier new,courier,monospace;">fillStyle</span>:
	</p>

	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
ctx.fillStyle = "orange"; 
ctx.fillStyle = "#FFA500"; 
ctx.fillStyle = "rgb(255, 165, 0)"; 
ctx.fillStyle = "rgba(255, 165, 0, 1)";
</pre>
</div>

<div id="wmd-preview-section-38">
	<h3 id="تطبيق-الألوان-على-شكل-باستخدام-الخاصية-fillstyle">
		تطبيق الألوان على شكل باستخدام الخاصية FillStyle
	</h3>

	<p>
		سأعرض مثالًا لكيفية ملء شكل باستخدام مجموعة مستطيلات بألوان مختلفة ليبدو شكل متعدد الألوان. 
	</p>

	<p>
		سيتم إنشاء حلقتي تكرار وذلك لتوليد مجموعة ألوان RGB مختلفة بتغيير قيمة red وgreen باستخدام المتغيرين <strong>i</strong> و <strong>j</strong> وترك القيمة blue ثابتة 0 سيبدو لك الشكل وكأنه منشأ باستخدام photoshop.
	</p>

	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
unction draw() { 
    var ctx = document.getElementById('canvas').getContext('2d'); 
    for (var i = 0; i &lt; 6; i++){ 
        for (var j = 0; j &lt; 6; j++){ 
            ctx.fillStyle = 'rgb(' + Math.floor(255-42.5*i) + ',' + Math.floor(255-42.5*j) + ',0)';
            ctx.fillRect(j*25, i*25, 25, 25); 
        } 
     } 
}</pre>

	<p>
		النتيجة:
	</p>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2016_01/56941aba55c98__9.png.60a6cd3b0f7470fd9c5ec2dbbbf6f02a.png"><img alt="56941aba58054__9.thumb.png.ff8a93abff3c7" class="ipsImage ipsImage_thumbnailed" data-fileid="11018" src="https://academy.hsoub.com/uploads/monthly_2016_01/56941aba58054__9.thumb.png.ff8a93abff3c78dec97407cb18fa0d17.png"></a>
	</p>
</div>

<div id="wmd-preview-section-40">
	<h3 id="تطبيق-الألوان-على-شكل-باستخدام-الخاصية-strokestyle">
		تطبيق الألوان على شكل باستخدام الخاصية StrokeStyle
	</h3>

	<p>
		سيكون المثال التالي مشابهًا للمثال السّابق مع تغيير الخاصيّة <span style="font-family:courier new,courier,monospace;">fillStyle</span> إلى <span style="font-family:courier new,courier,monospace;">strokeStyle</span> واستخدام الدالة <span style="font-family:courier new,courier,monospace;">arc</span> لرسم دوائر داخل مستطيل وتوليد مجموعة ألوان RGB مختلفة بتغيير قيمة green و blue باستخدام المتغيرين <strong>i</strong> و <strong>j</strong> وترك القيمة red ثابتة.
	</p>
</div>

<div id="wmd-preview-section-41">
	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
function draw() { 
    var ctx = document.getElementById('canvas').getContext('2d'); 
    for (var i = 0; i &lt; 6; i++){ 
        for (var j = 0; j &lt; 6; j++){ 
            ctx.strokeStyle = 'rgb(0,' + Math.floor(255-42.5*i) + ',' + Math.floor(255-42.5*j) + ')';
            ctx.beginPath(); 
            ctx.arc(12.5+j*25, 12.5+i*25, 10, 0, Math.PI*2,true); 
            ctx.stroke(); 
        } 
    } 
}</pre>

	<p>
		النتيجة:
	</p>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2016_01/56941abcb2558__10.png.800dee4aa79a6d777f51460157e86ecd.png"><img alt="56941abcb5454__10.thumb.png.fac29429162f" class="ipsImage ipsImage_thumbnailed" data-fileid="11019" src="https://academy.hsoub.com/uploads/monthly_2016_01/56941abcb5454__10.thumb.png.fac29429162fbba670b6f9c61a9225dc.png"></a>
	</p>
</div>

<div id="wmd-preview-section-42">
	<h2 id="الشفافية-transparency">
		الشفافية Transparency
	</h2>

	<p>
		بالإضافة لرسم الأشكال الواضحة يمكن أيضًا رسم أشكال شبه شفافة أو شفافة ويتم ذلك إما عن طريق تعيين الخاصيّة <span style="font-family:courier new,courier,monospace;">globalAlpha</span> أو عن طريق تحديد الشفافية في اللون RGB باستخدام الخاصيّتين <span style="font-family:courier new,courier,monospace;">StrokeStyle</span> أو <span style="font-family:courier new,courier,monospace;">FillStyle</span>:
	</p>

	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
globalAlpha = transparencyValue</pre>

	<p>
		تشبه الدالة<span style="font-family:courier new,courier,monospace;"> ()rgba</span> الدالة <span style="font-family:courier new,courier,monospace;">()rgb</span> باختلاف المعامل الأخير والذي يحدد قيمة الشفافية اللَّونية. تأخذ الشفافية قيمتها من 0.0 شفافية مطلقة إلى 1.0 شفافية معدومة.
	</p>
</div>

<div id="wmd-preview-section-43">
	<p>
		مثال لتحديد الشفافية باستخدام الدالة <span style="font-family: 'courier new', courier, monospace; line-height: 22.4px;">()rgba</span>:
	</p>

	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
ctx.strokeStyle = "rgba(255, 0, 0, 0.5)"; 
ctx.fillStyle = "rgba(255, 0, 0, 0.5)";
</pre>
</div>

<div id="wmd-preview-section-45">
	<h3 id="تحديد-الشفافية-باستخدام-globaalpha">
		تحديد الشفافية باستخدام GlobaAlpha
	</h3>

	<p>
		سأقوم بعرض مثال لرسم 4 مربعات متلاصقة وبألوان مختلفة ليتم تشكيل مربع كبير ثم تطبيق شفافية بشكل دوائر متدرجة الأحجام مركزها هي نقطة تلاقي المربعات (مركز المربع) وذلك عن طريق إنشاء حلقة تكرار ورسم الدوائر بقطر متزايد فوق بعضها البعض.
	</p>

	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
function draw() { 
    var ctx = document.getElementById('canvas').getContext('2d'); 
    ctx.fillStyle = '#FD0'; 
    ctx.fillRect(0, 0, 75, 75); 
    ctx.fillStyle = '#6C0'; 
    ctx.fillRect(75, 0, 75, 75); 
    ctx.fillStyle = '#09F'; 
    ctx.fillRect(0, 75, 75, 75); 
    ctx.fillStyle = '#F30'; 
    ctx.fillRect(75, 75, 75, 75); 
    ctx.fillStyle = '#FFF'; 
    ctx.globalAlpha = 0.2; 
    for (i = 0; i &lt; 7; i++){ 
        ctx.beginPath(); 
        ctx.arc(75, 75, 10+10*i, 0, Math.PI*2, true); 
        ctx.fill(); 
    } 
}</pre>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2016_01/56941abe171eb__11.png.0bfe4281c493e11dfca21c2b9a227ccf.png"><img alt="56941abe195fb__11.thumb.png.a678f2c89ee9" class="ipsImage ipsImage_thumbnailed" data-fileid="11020" src="https://academy.hsoub.com/uploads/monthly_2016_01/56941abe195fb__11.thumb.png.a678f2c89ee9e58147cbd2bc0579e953.png"></a>
	</p>
</div>

<div id="wmd-preview-section-47">
	<h3 id="تحديد-الشفافية-باستخدام-rgba">
		تحديد الشفافية باستخدام ()RGBA
	</h3>

	<p>
		سأقوم بعرض مثالًا مشابهًا للمثال السّابق ولكن بدلًا من رسم دوائر فوق بعضها بقطر متزايد سأرسم مستطيلات بشفافية متزايدة (زيادة التعتيم) باستخدام <span style="font-family:courier new,courier,monospace;">()rgba</span>:
	</p>

	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
function draw() { 
    var ctx = document.getElementById('canvas').getContext('2d'); 
    ctx.fillStyle = 'rgb(255, 221, 0)'; 
    ctx.fillRect(0, 0, 150, 37.5); 
    ctx.fillStyle = 'rgb(102, 204, 0)'; 
    ctx.fillRect(0, 37.5, 150, 37.5); 
    ctx.fillStyle = 'rgb(0, 153, 255)'; 
    ctx.fillRect(0, 75, 150, 37.5); 
    ctx.fillStyle = 'rgb(255, 51, 0)'; 
    ctx.fillRect(0, 112.5, 150, 37.5); 
    for (var i = 0; i &lt; 10; i++){ 
        ctx.fillStyle = 'rgba(255, 255, 255,'+(i+1)/10+')'; 
        for (var j = 0; j &lt; 4; j++){ 
            ctx.fillRect(5+i*14, 5+j*37.5, 14, 27.5); 
        } 
    } 
}</pre>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2016_01/56941ac5967e0__12.png.b01126f73580de71a6ec6d6a9f41989c.png"><img alt="56941ac5983b5__12.thumb.png.e27ec4f68798" class="ipsImage ipsImage_thumbnailed" data-fileid="11021" src="https://academy.hsoub.com/uploads/monthly_2016_01/56941ac5983b5__12.thumb.png.e27ec4f6879802b2781a197ded00b60f.png"></a>
	</p>
</div>

<div id="wmd-preview-section-49">
	<h2 id="تصاميم-وتنسيقات-الخطوط">
		تصاميم وتنسيقات الخطوط
	</h2>

	<p>
		يمكنك إنشاء ورسم خطوط بأشكال وتنسيقات مختلفة باستخدام مجموعة من الخصائص: 
	</p>

	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
lineWidth = value </pre>

	<p>
		تحدد سمك الخط المراد رسمه:
	</p>

	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
lineCap = type </pre>

	<p>
		تحدد مظهر نهاية الخط:
	</p>

	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
lineJoin = type </pre>

	<p>
		تحدد مظهر الزوايا عند الخطوط المتلاقية:
	</p>

	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
getLineDash() </pre>

	<p>
		تُرجع مصفوفة لخط من نمط dashes تحوي على أرقام تحدد المسافات لتناوب رسم الخط والمسافة:
	</p>

	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
setLineDash(segments) </pre>

	<p>
		تحدد الخط الحالي ليأخذ نمط dash:
	</p>

	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
lineDashOffset = value </pre>

	<p>
		تحدد أين ستبدأ مصفوفة النمط dash على الخط.
	</p>
</div>

<div id="wmd-preview-section-50">
	<h3 id="خاصية-linewidth">
		خاصية lineWidth
	</h3>

	<p>
		هذه الخاصيّة تُحدد سمك الخط الحالي وتأخذ قيم موجبة، القيمة الافتراضية لها هي 1.0.
	</p>

	<p>
		عرض الخط هو سمك الحواف Stroke التي تتركز على مسار معين. المثال التالي يعرض 10 خطوط مسقيمة ذات سمك متزايد.
	</p>

	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
function draw() { 
    var ctx = document.getElementById('canvas').getContext('2d'); 
    for (var i = 0; i &lt; 10; i++){ 
        ctx.lineWidth = 1+i; 
        ctx.beginPath(); 
        ctx.moveTo(5+i*14, 5); 
        ctx.lineTo(5+i*14, 140); 
        ctx.stroke(); 
    } 
}</pre>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2016_01/56941ac7e18cc__13.png.4e388d79e49617aa8fae3ff57f127153.png"><img alt="56941ac7e4036__13.thumb.png.96864ced1c40" class="ipsImage ipsImage_thumbnailed" data-fileid="11022" src="https://academy.hsoub.com/uploads/monthly_2016_01/56941ac7e4036__13.thumb.png.96864ced1c4035d0efd30902dca869c8.png"></a>
	</p>
</div>

<div id="wmd-preview-section-52">
	<h3 id="خاصية-linecap">
		خاصية lineCap
	</h3>

	<p>
		تحدد الخاصيّة <span style="font-family:courier new,courier,monospace;">lineCap</span> كيف ستُرسم النقاط النهائية للخط حيث تأخذ الخاصيّة <span style="font-family:courier new,courier,monospace;">lineCap</span> ثلاث قيم butt ،round وsquare. القيمة الافتراضية هي <strong>butt</strong>.
	</p>

	<ul><li>
			<strong>butt:</strong> تحدد نهايات الخطوط لتكون مربعة. 
		</li>
		<li>
			<strong>round: </strong>تحدد نهايات الخطوط لتكون دائرية. 
		</li>
		<li>
			<strong>square: </strong>تقوم بإنشاء مربع بنفس عرض الخط وارتفاع يساوي نصف سماكة الخط وتضيفه عند نهاية الخط.
		</li>
	</ul><p>
		سأقوم بعرض مثال يرسم ثلاثة خطوط بقيم <span style="font-family:courier new,courier,monospace;">lineCap</span> مختلفة سيتم تحديد بداية ونهاية الخطوط بواسطة دليلن (خطين أفقيين) لتمييز الفرق بين الخطوط الثلاثة:
	</p>

	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
function draw() { 
var ctx = document.getElementById(‘canvas’).getContext(‘2d’); 
var lineCap = [‘butt’,’round’,’square’];

// Draw guides 
ctx.strokeStyle = ‘#09f’; 
ctx.beginPath(); 
ctx.moveTo(10,10); 
ctx.lineTo(140,10); 
ctx.moveTo(10,140); 
ctx.lineTo(140,140); 
ctx.stroke();

// Draw lines 
ctx.strokeStyle = ‘black’; 
for (var i=0;i
}
</pre>
</div>

<div id="wmd-preview-section-53">
	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2016_01/56941ac91822a__14.png.34d8b427aa070a5662f822fa87695430.png"><img alt="56941ac91a21f__14.thumb.png.3ef6f3e27ccd" class="ipsImage ipsImage_thumbnailed" data-fileid="11023" src="https://academy.hsoub.com/uploads/monthly_2016_01/56941ac91a21f__14.thumb.png.3ef6f3e27ccd9734c4020faa0e63f91a.png"></a>
	</p>

	<p>
		كما تلاحظ في الخط اليساري رُسم بقيمة butt. الخط في المنتصف رُسم بقيمة round الخط الأخير رسم بقيمة square والتي تقوم بإنشاء مربع بنفس عرض الخط وارتفاع يساوي نصف سماكة الخط.
	</p>
</div>

<div id="wmd-preview-section-54">
	<h3 id="خاصية-linejoin">
		خاصية lineJoin
	</h3>

	<p>
		تحدد الخاصيّة <span style="font-family:courier new,courier,monospace;">lineJoin</span> كيف لمسارين (خطوط، أقواس، منحنيات) أن يرتبطا معًا أي أنها تحدد شكل نقطة الارتباط بين مسارين. 
	</p>

	<p>
		تأخذ الخاصيّة <span style="font-family:courier new,courier,monospace;">lineJoin</span> ثلاث قيم round ،bevel وmiter. القيمة الافتراضية لـ <span style="font-family:courier new,courier,monospace;">lineJoin</span> هي <strong>miter</strong>.
	</p>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2016_01/56941aca0cded__15.png.ae4a2a440933e27762cc18950b7dd80d.png"><img alt="56941aca0ecb7__15.thumb.png.18e3b5ed135c" class="ipsImage ipsImage_thumbnailed" data-fileid="11024" src="https://academy.hsoub.com/uploads/monthly_2016_01/56941aca0ecb7__15.thumb.png.18e3b5ed135c554cd138818d26e825d1.png"></a>
	</p>

	<ul><li>
			<strong>Round: </strong>تقوم بتدوير زوايا الشكل عن طريق ملئها بقطاعات دائرية نصف قطر هذه الزوايا الدائرية يساوي عرض الخط.
		</li>
		<li>
			<strong>Bevel: </strong>تقوم بسد المنطقة المثلثية الناتجة من تلاقي خطين بحيث تقوم بحذف المثلث الناتج من تلاقي الخطين. وملأ المساحة المتبقية.
		</li>
		<li>
			<strong>Miter: </strong>تقوم بملأ المساحة بين نهايتي الخطين المتلاقين لتشكل مثلث. 
		</li>
	</ul><p>
		المثال التالي يوضح عمل كل واحد من تلك الخصائص:
	</p>
</div>

<div id="wmd-preview-section-55">
	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
function draw() { 
    var ctx = document.getElementById('canvas').getContext('2d'); 
    var lineJoin = ['round', 'bevel', 'miter'];  
    ctx.lineWidth = 10; 
    for (var i = 0; i &lt; lineJoin.length; i++){ 
        ctx.lineJoin = lineJoin[i]; 
        ctx.beginPath(); 
        ctx.moveTo(-5, 5+i*40); 
        ctx.lineTo(35, 45+i*40); 
        ctx.lineTo(75, 5+i*40); 
        ctx.lineTo(115, 45+i*40); 
        ctx.lineTo(155, 5+i*40); 
        ctx.stroke(); 
    } 
}</pre>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2016_01/56941acb4edd3__16.png.bd2a641615c57662beeaf1a54f1abd39.png"><img alt="56941acb512be__16.thumb.png.03624508349b" class="ipsImage ipsImage_thumbnailed" data-fileid="11025" src="https://academy.hsoub.com/uploads/monthly_2016_01/56941acb512be__16.thumb.png.03624508349b4c99e6dea56e4cb567a5.png"></a>
	</p>
</div>

<div id="wmd-preview-section-56">
	<h3 id="استخدام-الشرطات-dashes">
		استخدام الشرطات dashes
	</h3>

	<p>
		يمكنك تحديد الخط ليأخذ نمط الشرطات dashed باستخدام الدالة <span style="font-family:courier new,courier,monospace;">setLineDash</span> والخاصيّة <span style="font-family:courier new,courier,monospace;">lineDashOffset</span> لتحديد نمط الشرطات للخطوط. 
	</p>

	<p>
		تأخذ الدالة <span style="font-family:courier new,courier,monospace;">setLineDash</span> قائمة list من الأرقام التي تحدد المسافات لتناوب رسم الخط والمسافة. 
	</p>

	<p>
		الخاصيّة <span style="font-family:courier new,courier,monospace;">lineDashOffset</span> تحدد القيمة التي سيبدأ عندها النمط. 
	</p>

	<p>
		في المثال أدناه سأقوم بإنشاء شكل يشبه تأثير مسيرة النمل مع تأثير حركي عادةً يوجد في أداة التحديد selection tool في برامج الجرافيكس.( سيتم شرح التأثيرات الحركية بالتفصيل لاحقًا)
	</p>

	<p>
		 
	</p>
</div>

<div id="wmd-preview-section-57">
	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
var ctx = document.getElementById('canvas').getContext('2d'); 
var offset = 0; 

function draw() { 
    ctx.clearRect(0, 0, canvas.width, canvas.height); 
    ctx.setLineDash([4, 2]); 
    ctx.lineDashOffset = -offset; 
    ctx.strokeRect(10, 10, 100, 100); 
} 

function march() { 
    offset++;   
    if (offset &gt; 16) { 
        offset = 0; 
    } 
    draw(); 
    setTimeout(march, 20); 
} 

march();</pre>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2016_01/56941ad07aed8__17.png.9979910f75910c1548bfac66aab27b9e.png"><img alt="56941ad07cc2a__17.thumb.png.ff074cc15061" class="ipsImage ipsImage_thumbnailed" data-fileid="11026" src="https://academy.hsoub.com/uploads/monthly_2016_01/56941ad07cc2a__17.thumb.png.ff074cc15061689e33b29fdaefd0d475.png"></a>
	</p>
</div>

<div id="wmd-preview-section-58">
	<h2 id="التدرجات-اللونية-gradient">
		التدرجات اللونية Gradient
	</h2>

	<p>
		يوجد نوعان من التدرّجات اللَّونية في canvas: 
	</p>

	<ol><li>
			 تدرجات لونية خطية Linear Gradient.
		</li>
		<li>
			وتدرجات لونية شعاعية Radial Gradient.
		</li>
	</ol><p>
		يتم إنشاء تدرُّجات لونية عن طريق إنشاء كائن <span style="font-family:courier new,courier,monospace;">CanvasGradient</span> باستخدام أحد الدالتين التالييتن ثم نطبق أحد الخاصيّتين <span style="font-family:courier new,courier,monospace;">fillStyle</span> أو <span style="font-family:courier new,courier,monospace;">strokeStyle</span> على الكائن. 
	</p>

	<h3>
		1- الدالة CreateLinearGradient
	</h3>

	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
createLinearGradient(x1, y1, x2, y2) </pre>

	<p>
		تنشئ كائن من نوع linear gradient حيث تمثل x1, y1 نقطة البداية و x2, y2 نقطة النهاية. 
	</p>

	<h3>
		2- الدالة Create RadialGradient
	</h3>

	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
createRadialGradient(x1, y1, r1, x2, y2, r2) </pre>

	<p>
		تنشئ تدرج لوني شعاعي حيث تمثل المعاملات دائرتين x1, y1 مركز الدائرة الأولى ونصف قطرها r1 و x2, y2 مركز الدائرة الثانية ونصف قطرها هو r2. 
	</p>

	<p>
		<strong>مثال:</strong>
	</p>

	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
var lineargradient = ctx.createLinearGradient(0, 0, 150, 150); 
var radialgradient = ctx.createRadialGradient(75, 75, 0, 75, 75, 100);</pre>

	<p>
		بعد إنشاء نوع التدرّج اللَّوني يمكنك تطبيق الألوان عليه باستخدام الدالة <span style="font-family:courier new,courier,monospace;">()addColorStop</span>:
	</p>

	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
gradient.addColorStop(position, color)</pre>

	<ul><li>
			المعامل <span style="font-family:courier new,courier,monospace;">position</span> هو رقم بين 0.0 و 1.0 ويحدد الوضع النسبي للون في الإنحدار. 
		</li>
		<li>
			المعامل <span style="font-family:courier new,courier,monospace;">color</span> يحدد اللون ويجب أن يكون نص string ممثل بـ CSS.
		</li>
	</ul><p>
		يمكن إضافة العديد من نقاط اللّون إلى التدرّج فيما يلي مثال لانحدار خطي بسيط من اللّونين الأبيض والأسود:
	</p>

	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
var lineargradient = ctx.createLinearGradient(0, 0, 150, 150); 
lineargradient.addColorStop(0, 'white'); 
lineargradient.addColorStop(1, 'black');
</pre>
</div>

<div id="wmd-preview-section-62">
	<h3 id="تطبيق-تدرج-لوني-خطي-linear-gradient-مع-الخاصيتين-fillstyle-و-strokstyle">
		تطبيق تدرج لوني خطي Linear Gradient مع الخاصيتين fillStyle و strokStyle
	</h3>

	<p>
		كما ستلاحظ في المثال التالي أن كلا الخاصيّتين <span style="font-family:courier new,courier,monospace;">fillStyle</span> و <span style="font-family:courier new,courier,monospace;">strokeStyle</span> تأخذان كائنًا من نوع <span style="font-family:courier new,courier,monospace;">canvasGradient.</span>
	</p>
</div>

<div id="wmd-preview-section-63">
	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
function draw() { 
    var ctx = document.getElementById('canvas').getContext('2d'); 

    var lingrad = ctx.createLinearGradient(0, 0, 0, 150); 
    lingrad.addColorStop(0, '#00ABEB'); 
    lingrad.addColorStop(0.5, '#fff'); 
    lingrad.addColorStop(0.5, '#26C000'); 
    lingrad.addColorStop(1, '#fff'); 

    var lingrad2 = ctx.createLinearGradient(0, 50, 0, 95); 
    lingrad2.addColorStop(0.5, '#000'); 
    lingrad2.addColorStop(1, 'rgba(0, 0, 0, 0)'); 
 
    ctx.fillStyle = lingrad; 
    ctx.strokeStyle = lingrad2; 
    ctx.fillRect(10, 10, 130, 130); 
    ctx.strokeRect(50, 50, 50, 50); 
}</pre>

	<p>
		المثال أعلاه يشرح كيفيّة عمل تدرج لوني خطي يمثل لون السماء والأرضية عن طريق إنشاء متغير <span style="font-family:courier new,courier,monospace;">lingrad</span> ثم استدعاء الدالة <span style="font-family:courier new,courier,monospace;">()addColorStop</span> لتطبيق الألوان الأزرق والأبيض ثم الأخضر والأبيض ثم إسنادها للخاصية <span style="font-family:courier new,courier,monospace;">fillStlye</span> ثم إنشاء تدرج لوني أسود عن طريق إنشاء متغير <span style="font-family:courier new,courier,monospace;">2lingrad</span> وتطبيق نقاط لونية باللون الأسود ثم إسناده للخاصية <span style="font-family:courier new,courier,monospace;">strokeStyle</span>. 
	</p>

	<p>
		أخيرًا رسم الأشكال بالإحداثيات المناسبة:
	</p>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2016_01/56941ad27a234__18.png.69224411a9adcb8cee11a13143f6314f.png"><img alt="56941ad27c0b4__18.thumb.png.e195083a3817" class="ipsImage ipsImage_thumbnailed" data-fileid="11027" src="https://academy.hsoub.com/uploads/monthly_2016_01/56941ad27c0b4__18.thumb.png.e195083a3817473c9c5c0b3962881034.png"></a>
	</p>
</div>

<div id="wmd-preview-section-64">
	<h3 id="تطبيق-تدرج-لوني-شعاعي-radial-gradient-مع-الخاصيتين-fillstyle-و-strokstyle">
		تطبيق تدرج لوني شعاعي Radial Gradient مع الخاصيتين fillStyle و strokStyle
	</h3>

	<p>
		لفهم كيفية عمل التدرّج اللَّوني الشّعاعي لابد من عرض مثال. 
	</p>

	<p>
		المثال أدناه يحدد أربعة تدرجات شعاعية مختلفة حيث سيتم إنشاء تدرّجات شعاعية أكثر تعقيدًا عن التدرّجات الشّعاعية الكلاسيكية.
	</p>

	<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
function draw() { 
    var ctx = document.getElementById('canvas').getContext('2d'); 

    var radgrad = ctx.createRadialGradient(45, 45, 10, 52, 50, 30); 
    radgrad.addColorStop(0, '#A7D30C'); 
    radgrad.addColorStop(0.9, '#019F62'); 
    radgrad.addColorStop(1, 'rgba(1,159,98,0)'); 

    var radgrad2 = ctx.createRadialGradient(105, 105, 20, 112, 120, 50); 
    radgrad2.addColorStop(0, '#FF5F98'); 
    radgrad2.addColorStop(0.75, '#FF0188'); 
    radgrad2.addColorStop(1, 'rgba(255,1,136,0)'); 

    var radgrad3 = ctx.createRadialGradient(95, 15, 15, 102, 20, 40); 
    radgrad3.addColorStop(0, '#00C9FF'); 
    radgrad3.addColorStop(0.8, '#00B5E2'); 
    radgrad3.addColorStop(1, 'rgba(0,201,255,0)'); 

    var radgrad4 = ctx.createRadialGradient(0, 150, 50, 0, 140, 90);  
    radgrad4.addColorStop(0, '#F4F201'); 
    radgrad4.addColorStop(0.8, '#E4C700'); 
    radgrad4.addColorStop(1, 'rgba(228,199,0,0)'); 

    ctx.fillStyle = radgrad4; 
    ctx.fillRect(0, 0, 150, 150); 
    ctx.fillStyle = radgrad3; 
    ctx.fillRect(0, 0, 150, 150); 
    ctx.fillStyle = radgrad2; 
    ctx.fillRect(0, 0, 150, 150); 
    ctx.fillStyle = radgrad; 
    ctx.fillRect(0, 0, 150, 150); 
}</pre>

	<p>
		كما تلاحظ تم إنشاء 4 تدرجات لونية شعاعية وتحديد إحداثيات ونصف قطر كل من الدائرتين اللَّونيتين لكل تدرج شعاعي.
	</p>
</div>

<div id="wmd-preview-section-65">
	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2016_01/56941ad3adb23__19.png.8a2cc529032935bfc24b309fc9eacc3a.png"><img alt="56941ad3b092a__19.thumb.png.8e85da85be9b" class="ipsImage ipsImage_thumbnailed" data-fileid="11028" src="https://academy.hsoub.com/uploads/monthly_2016_01/56941ad3b092a__19.thumb.png.8e85da85be9bf64f59d77da6ae20dac8.png"></a>
	</p>

	<p>
		كانت هذه المعلومات بمثابة طرف الخيط الذي يقودك للبدء في تعلُّم رسم الأشكال على Canvas كالمحترفين. يحتاج الأمر منك للكثير من التجريب والتخيل لتتقن العمل على هذه الأداة واكتشاف ميزاتها.
	</p>

	<p>
		<a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API" rel="external nofollow">المصادر</a>
	</p>
</div>
]]></description><guid isPermaLink="false">239</guid><pubDate>Tue, 12 Jan 2016 21:36:00 +0000</pubDate></item><item><title>&#x627;&#x644;&#x62A;&#x639;&#x627;&#x645;&#x644; &#x645;&#x639; &#x639;&#x646;&#x635;&#x631; Canvas &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A; (&#x631;&#x633;&#x645; &#x627;&#x644;&#x623;&#x634;&#x643;&#x627;&#x644;)</title><link>https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%B9%D9%86%D8%B5%D8%B1-canvas-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-%D8%B1%D8%B3%D9%85-%D8%A7%D9%84%D8%A3%D8%B4%D9%83%D8%A7%D9%84-r209/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_11/canvas-javascript.png.f988ffe55e2f82dcf9c6edc5d0d3ea8b.png" /></p>

<div id="wmd-preview-section-24">
	<p id="التعامل-مع-عنصر-الرقعة-canvas-باستخدام-جافا-سكربت-رسم-الأشكال">
		<a href="https://academy.hsoub.com/programming/javascript/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%B9%D9%86%D8%B5%D8%B1-canvas-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%AC%D8%A7%D9%81%D8%A7-%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r207/">تعرَّفنا في المقال السّابق على العنصر Canvas</a> الذي أُضيف إلى HTML5 ليوفّر أداة ومساحة لرسم الأشكال والتصاميم باستخدام جافاسكربت. 
	</p>

	<p>
		سنتعلم في هذا الدّرس كيفية رسم الأشكال على Canvas باستخدام جافا سكربت مثل الدوائر، المثلَّثات والمستطيلات وسنتعرف على المنحنيات Curves لرسم أشكال أكثر تعقيدًا.
	</p>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_11/canvas-javascript.png.b545d228b73a6bc7b1b2a35d7088cfc1.png"><img alt="canvas-javascript.thumb.png.e54aceb6e40c" class="ipsImage ipsImage_thumbnailed" data-fileid="8240" src="https://academy.hsoub.com/uploads/monthly_2015_11/canvas-javascript.thumb.png.e54aceb6e40ca142323fefa42fa2eb6d.png"></a>
	</p>
</div>

<div id="wmd-preview-section-25">
	<h2 id="الشبكة-the-grid">
		الشبكة The grid
	</h2>

	<p>
		إن أي عنصر يتم إضافته أو رسمه على Canvas يُحَدّد موقعه بواسطة الزَّاوية اليسارية العليا (0, 0) أي بإحداثيات (x, y) بحيث أنه يبعد عن المركز (0, 0) بمقدار (x, y).
	</p>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f20d739b__1.png.aafb1d57a05c797c2ce29c704a53ed4e.png"><img alt="565c4f20d8f4b__1.thumb.png.6bafa9b6f72d6" class="ipsImage ipsImage_thumbnailed" data-fileid="8221" src="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f20d8f4b__1.thumb.png.6bafa9b6f72d6cd640daa4b4f3dd8300.png"></a>
	</p>
</div>

<div id="wmd-preview-section-26">
	<h2 id="رسم-المستطيلات-rectangles">
		رسم المستطيلات Rectangles
	</h2>

	<p>
		توفر canvas ثلاث دوال لرسم المستطيلات وجميعها تأخذ معاملات argumrnts مماثلة. 
	</p>

	<p>
		الإحداثيات (x, y) تحدد موقع المستطيل بالنسبة للمركز (0, 0) والذي يحدَّد بالزَّاوية اليسارية العليا للـ Canvas، العرض width والطول height تحددان قياس المستطيل. 
	</p>

	<ul><li>
			الدَّالة <strong><span style="font-family:courier new,courier,monospace;">()fillRect</span></strong> ترسم مستطيلًا ذي مساحة لونية solid color. 
		</li>
		<li>
			الدَّالة <strong><span style="font-family:courier new,courier,monospace;">()strokeRect</span></strong> ترسم مستطيلًا Storke (مُفرغًا) ذي حواف فقط outline. 
		</li>
		<li>
			الدَّالة <strong><span style="font-family:courier new,courier,monospace;">()clearRect</span></strong> تقوم بمسح مستطيل محدّد بالمعاملات x, y) ،width ،height) أي تجعله شفافًا Transparent.
		</li>
	</ul><p>
		ولا ننسى طبعا الدَّالة <span style="font-family:courier new,courier,monospace;">()draw</span> والتي تدير جميع عمليات الرَّسم على الـ canvas في الجافاسكربت.
	</p>

	<p>
		سنرى كيفية رسم المستطيلات باستخدام الدَّوال الثلاث أعلاه. السكربت التالي يرسم ثلاثة مستطيلات بإحداثيات وقياسات مختلفة :
	</p>

	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4">
<span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"application/javascript"</span><span class="tag">&gt;</span><span class="pln"> 
</span><span class="kwd">function</span><span class="pln"> draw</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
  </span><span class="kwd">var</span><span class="pln"> canvas </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">"canvas"</span><span class="pun">);</span><span class="pln"> 
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">canvas</span><span class="pun">.</span><span class="pln">getContext</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
    </span><span class="kwd">var</span><span class="pln"> ctx </span><span class="pun">=</span><span class="pln"> canvas</span><span class="pun">.</span><span class="pln">getContext</span><span class="pun">(</span><span class="str">"2d"</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">fillStyle </span><span class="pun">=</span><span class="pln"> </span><span class="str">"rgb(200,0,0)"</span><span class="pun">;</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">fillRect</span><span class="pun">(</span><span class="lit">10</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">,</span><span class="pln"> </span><span class="lit">200</span><span class="pun">,</span><span class="pln"> </span><span class="lit">200</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">clearRect</span><span class="pun">(</span><span class="lit">30</span><span class="pun">,</span><span class="pln"> </span><span class="lit">30</span><span class="pun">,</span><span class="pln"> </span><span class="lit">150</span><span class="pun">,</span><span class="pln"> </span><span class="lit">150</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">strokeRect</span><span class="pun">(</span><span class="lit">50</span><span class="pun">,</span><span class="pln"> </span><span class="lit">50</span><span class="pun">,</span><span class="pln"> </span><span class="lit">60</span><span class="pun">,</span><span class="pln"> </span><span class="lit">60</span><span class="pun">);</span><span class="pln"> 
  </span><span class="pun">}</span><span class="pln"> 
</span><span class="pun">}</span><span class="pln"> 
</span><span class="tag">&lt;/script&gt;</span></pre>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f21b3099__2.png.986965baa9b0df75fdc0bd1290485084.png"><img alt="565c4f21b488b__2.thumb.png.72450aa485f7d" class="ipsImage ipsImage_thumbnailed" data-fileid="8222" src="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f21b488b__2.thumb.png.72450aa485f7d718f768c9a285303cc3.png"></a>
	</p>
</div>

<div id="wmd-preview-section-27">
	<ul><li>
			باستخدام <span style="font-family:courier new,courier,monospace;">()fillRect</span> تم رسم مستطيل ذو مساحة لونية حمراء بقياس 200*200 عند الإحداثيات (10,10).
		</li>
		<li>
			باستخدام <span style="font-family:courier new,courier,monospace;">()clearRect</span> تم رسم مستطيل بلا لون (شفاف) بقياس 150*150 عند الإحداثيات (30,30).
		</li>
		<li>
			باستخدام<span style="font-family:courier new,courier,monospace;"> ()storkRect</span> تم رسم مستطيل stroke مُفرغ ذو حواف بقياس 60*60 عند الإحداثيات (50,50).
		</li>
	</ul></div>

<div id="wmd-preview-section-28">
	<h2 id="رسم-المسارات-paths">
		رسم المسارات Paths
	</h2>

	<p>
		المسارات paths هي عبارة عن مجموعة من النقاط متصلة مع بعضها البعض بواسطة خطوط صغيرة segments لتقوم بتشكيل رسومات مختلفة كأشكال منحنية، أشكال هندسية…الخ. يمكن أن يكون المسار مفتوحًا مثل نصف دائرة او مغلقًا كالمثلَّث.
	</p>

	<p>
		هناك 4 خطوات أساسية لرسم المسارات حيث تُنفّذ مجموعة من الدَّوال بالتّرتيب للحصول على المسار بالشكل المطلوب.
	</p>

	<ul><li>
			<strong><span style="font-family:courier new,courier,monospace;">()beginPath</span></strong> تقوم هذه الدَّالة بإنشاء المسار بحيث يتم رسم المسار وتخزين نقاطه في قائمة List.
		</li>
		<li>
			the methods هي مجموعة من الدَّوال التي تقوم بإنشاء أشكال أساسية مثل الدَّالة <span style="font-family:courier new,courier,monospace;">arc</span> التي ترسم قوس والدّالة <span style="font-family:courier new,courier,monospace;">lineTo </span>التي ترسم خط مستقيم.
		</li>
		<li>
			<strong><span style="font-family:courier new,courier,monospace;">()moveTo</span></strong> تقوم في كل مرة برسم نقطة انطلاق جديدة لبدء الرَّسم منها.
		</li>
		<li>
			<strong><span style="font-family:courier new,courier,monospace;">()closePath</span></strong> تقوم بإغلاق المسار ليتم الرَّسم خارج المسار بعدها أي البدء بمسار جديد.
		</li>
		<li>
			<strong><span style="font-family:courier new,courier,monospace;">()stroke</span></strong> تحول المسار المرسوم إلى شكل مُفرَّغ ذو حواف أي دون ملأ المسار.
		</li>
		<li>
			<strong><span style="font-family:courier new,courier,monospace;">()fill</span></strong> تحول المسار المرسوم إلى مسار ممتلئ بمساحة لونية solid.
		</li>
	</ul><p>
		الخطوة الأولى لإنشاء مسار path هي استدعاء الدَّالة <span style="font-family:courier new,courier,monospace;">()beginPath</span> (بشكل ضمني المسارات تُخزَّن بشكل مسارات جزئية في مصفوفة أو قائمة List مثل خطوط أو منحنيات..الخ) والتي بمجملها مسؤولة عن تكوين الشكل.
	</p>

	<p>
		في كل مرة تتم فيها استدعاء الدَّالة <span style="font-family: 'courier new', courier, monospace; line-height: 24.8889px;">()beginPath</span> يتم فيها إعادة إنشاء مصفوفة أو قائمة List جديدة ويمكننا البدء برسم شكل جديد.
	</p>

	<p>
		الخطوة الثانية هي استدعاء إحدى الدَّوال التي تقوم بتحديد المسار الذي سيُرسم مثل الدَّالة <span style="font-family:courier new,courier,monospace;">()moveTo</span> أو الدَّالة <span style="font-family:courier new,courier,monospace;">()lineTo</span>.
	</p>

	<p>
		الخطوة الثالثة هي استدعاء إحدى الدالتين <span style="font-family:courier new,courier,monospace;">()storke</span> أو <span style="font-family:courier new,courier,monospace;">()fill</span>.
	</p>

	<p>
		الخطوة الرابعة وهي خطوة اختيارية يتم فيها استدعاء الدَّالة <span style="font-family:courier new,courier,monospace;">()closePath</span> هذه الدَّالة تقوم بإغلاق الشكل عن طريق رسم خط مستقيم من النُّقطة الحالية التي توقف عندها الرَّسم إلى نقطة البداية التي بدأ عندها رسم المسار.
	</p>

	<h3>
		ملاحظات:
	</h3>

	<ol><li>
			في حين كان الشكل قد أُغلق أثناء الرَّسم أو بقيت نقطة واحدة في القائمة List فهذه الدَّالة لن تقوم بعمل أي شيء.
		</li>
		<li>
			عند استدعاء الدَّالة <span style="font-family:courier new,courier,monospace;">()fill</span> فإن الأشكال المفتوحة ستُغلق تلقائيًّا أي لن يكون هناك داعي لاستدعاء الدَّالة <span style="font-family: 'courier new', courier, monospace; line-height: 24.8889px;">()closePath</span> ولكن لا تنطبق هذه الحالة عند استدعاء الدَّالة <span style="font-family: 'courier new', courier, monospace; line-height: 24.8889px;">()storke</span>.
		</li>
	</ol></div>

<div id="wmd-preview-section-29">
	<h3 id="1-رسم-مثلث">
		رسم مثلث
	</h3>

	<p>
		اعتمادًا على خطوات إنشاء المسارات أعلاه سأقوم بإنشاء مسار مثلَّث كما في السكربت التالي:
	</p>

	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4">
<span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"application/javascript"</span><span class="tag">&gt;</span><span class="pln"> 
</span><span class="kwd">function</span><span class="pln"> draw</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
  </span><span class="kwd">var</span><span class="pln"> canvas </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">"canvas"</span><span class="pun">);</span><span class="pln"> 
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">canvas</span><span class="pun">.</span><span class="pln">getContext</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
    </span><span class="kwd">var</span><span class="pln"> ctx </span><span class="pun">=</span><span class="pln"> canvas</span><span class="pun">.</span><span class="pln">getContext</span><span class="pun">(</span><span class="str">"2d"</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">beginPath</span><span class="pun">();</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">moveTo</span><span class="pun">(</span><span class="lit">100</span><span class="pun">,</span><span class="pln"> </span><span class="lit">100</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">lineTo</span><span class="pun">(</span><span class="lit">300</span><span class="pun">,</span><span class="pln"> </span><span class="lit">200</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">lineTo</span><span class="pun">(</span><span class="lit">100</span><span class="pun">,</span><span class="pln"> </span><span class="lit">200</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">fillStyle </span><span class="pun">=</span><span class="pln"> </span><span class="str">"rgb(200,0,180)"</span><span class="pun">;</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">fill</span><span class="pun">();</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">closePath</span><span class="pun">();</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">beginPath</span><span class="pun">();</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">moveTo</span><span class="pun">(</span><span class="lit">100</span><span class="pun">,</span><span class="pln"> </span><span class="lit">300</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">lineTo</span><span class="pun">(</span><span class="lit">400</span><span class="pun">,</span><span class="pln"> </span><span class="lit">300</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">lineTo</span><span class="pun">(</span><span class="lit">400</span><span class="pun">,</span><span class="pln"> </span><span class="lit">200</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">fillStyle </span><span class="pun">=</span><span class="pln"> </span><span class="str">"rgb(140,50,80)"</span><span class="pun">;</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">fill</span><span class="pun">();</span><span class="pln"> 
  </span><span class="pun">}</span><span class="pln"> 
</span><span class="pun">}</span><span class="pln"> 
</span><span class="tag">&lt;/script&gt;</span></pre>

	<p>
		قمت بإنشاء مثلَّثين الأول عند النُّقطة (100, 100)، رسم خط مستقيم بواسطة الدَّالة <span style="font-family:courier new,courier,monospace;">()lineTo</span> إلى النُّقطة (300, 200)، خط مستقيم إلى النُّقطة (100, 200) ثم تحديد اللّون عن طريق الدَّالة<span style="font-family:courier new,courier,monospace;"> ()fillStyle</span> وبالنهاية استدعاء الدَّالة <span style="font-family:courier new,courier,monospace;">()fill</span> ليتم تلوين المسار والحصول على شكل مثلَّث. كذلك الأمر بالنسبة للمثلَّث الثاني.
	</p>
</div>

<div id="wmd-preview-section-30">
	<p>
		عند تشغيل المتصفّح يظهر المثلَّثان بهذا الشكل:
	</p>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f2280417_3.png.e6349c1cb16e1d86dba0b32ca225cad3.png"><img alt="565c4f2281fba_3.thumb.png.0d8d4ce1fb5630" class="ipsImage ipsImage_thumbnailed" data-fileid="8223" src="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f2281fba_3.thumb.png.0d8d4ce1fb5630adaa531f14546dee08.png"></a>
	</p>
</div>

<div id="wmd-preview-section-31">
	<h3 id="الرسم-بتحريك-القلم-moving-pen">
		الرسم بتحريك القلم moving pen
	</h3>

	<p>
		تخيل أنك تقوم برسم لوحة فنية كم مرة ستحتاج لترك نقطة رسم وتحريك القلم للبدء من نقطة جديدة، هذا ما تقوم به الدَّالة<span style="font-family:courier new,courier,monospace;"> ()moveTo</span> أي أنها تقوم بنقل نقطة بدء الرَّسم إلى نقطة (x, y) جديدة.
	</p>
</div>

<div id="wmd-preview-section-32">
	<p>
		عند إنشاء canvas أو عند استدعاء الدَّالة <span style="font-family:courier new,courier,monospace;">()beginPath</span> ستحتاج إلى استدعاء الدَّالة <span style="font-family:courier new,courier,monospace;">()moveTo</span> لتحديد نقطة البداية التي ستبدأ عندها الرَّسم. أو عندما تكون بحاجة لرسم مسارات متقطعة.
	</p>

	<p>
		للتوضيح أكثر سأقوم برسم وجه ضاحك smiley face وتلوينه كما في السكربت التالي:
	</p>

	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4">
<span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"application/javascript"</span><span class="tag">&gt;</span><span class="pln"> 
</span><span class="kwd">function</span><span class="pln"> draw</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
  </span><span class="kwd">var</span><span class="pln"> canvas </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'canvas'</span><span class="pun">);</span><span class="pln"> 
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">canvas</span><span class="pun">.</span><span class="pln">getContext</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
    </span><span class="kwd">var</span><span class="pln"> ctx </span><span class="pun">=</span><span class="pln"> canvas</span><span class="pun">.</span><span class="pln">getContext</span><span class="pun">(</span><span class="str">'2d'</span><span class="pun">);</span><span class="pln"> 

    ctx</span><span class="pun">.</span><span class="pln">beginPath</span><span class="pun">();</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">fillStyle </span><span class="pun">=</span><span class="pln"> </span><span class="str">"rgb(0, 0, 0)"</span><span class="pun">;</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">arc</span><span class="pun">(</span><span class="lit">75</span><span class="pun">,</span><span class="pln"> </span><span class="lit">75</span><span class="pun">,</span><span class="pln"> </span><span class="lit">50</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">PI </span><span class="pun">*</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">stroke</span><span class="pun">();</span><span class="pln">
    ctx</span><span class="pun">.</span><span class="pln">closePath</span><span class="pun">();</span><span class="pln"> 

    ctx</span><span class="pun">.</span><span class="pln">beginPath</span><span class="pun">();</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">fillStyle </span><span class="pun">=</span><span class="pln"> </span><span class="str">"rgb(250, 250, 0)"</span><span class="pun">;</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">arc</span><span class="pun">(</span><span class="lit">75</span><span class="pun">,</span><span class="pln"> </span><span class="lit">75</span><span class="pun">,</span><span class="pln"> </span><span class="lit">50</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">PI </span><span class="pun">*</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">fill</span><span class="pun">();</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">closePath</span><span class="pun">();</span><span class="pln"> 

    ctx</span><span class="pun">.</span><span class="pln">beginPath</span><span class="pun">();</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">fillStyle </span><span class="pun">=</span><span class="pln"> </span><span class="str">"rgb(250, 0, 0)"</span><span class="pun">;</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">moveTo</span><span class="pun">(</span><span class="lit">110</span><span class="pun">,</span><span class="pln"> </span><span class="lit">75</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">arc</span><span class="pun">(</span><span class="lit">75</span><span class="pun">,</span><span class="pln"> </span><span class="lit">75</span><span class="pun">,</span><span class="pln"> </span><span class="lit">35</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">PI</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">);</span><span class="pln">
    ctx</span><span class="pun">.</span><span class="pln">fill</span><span class="pun">();</span><span class="pln">
    ctx</span><span class="pun">.</span><span class="pln">closePath</span><span class="pun">();</span><span class="pln"> 

    ctx</span><span class="pun">.</span><span class="pln">moveTo</span><span class="pun">(</span><span class="lit">65</span><span class="pun">,</span><span class="pln"> </span><span class="lit">65</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">beginPath</span><span class="pun">();</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">fillStyle </span><span class="pun">=</span><span class="pln"> </span><span class="str">"rgb(0, 0, 0)"</span><span class="pun">;</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">arc</span><span class="pun">(</span><span class="lit">60</span><span class="pun">,</span><span class="pln"> </span><span class="lit">65</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">PI </span><span class="pun">*</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">fill</span><span class="pun">();</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">closePath</span><span class="pun">();</span><span class="pln"> 

    ctx</span><span class="pun">.</span><span class="pln">beginPath</span><span class="pun">();</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">moveTo</span><span class="pun">(</span><span class="lit">95</span><span class="pun">,</span><span class="pln"> </span><span class="lit">65</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">fillStyle </span><span class="pun">=</span><span class="pln"> </span><span class="str">"rgb(0, 0, 0)"</span><span class="pun">;</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">arc</span><span class="pun">(</span><span class="lit">90</span><span class="pun">,</span><span class="pln"> </span><span class="lit">65</span><span class="pun">,</span><span class="pln"> </span><span class="lit">5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">PI </span><span class="pun">*</span><span class="pln"> </span><span class="lit">2</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">fill</span><span class="pun">();</span><span class="pln">
    ctx</span><span class="pun">.</span><span class="pln">closePath</span><span class="pun">();</span><span class="pln"> 
  </span><span class="pun">}</span><span class="pln"> 
</span><span class="pun">}</span><span class="pln"> 
</span><span class="tag">&lt;/script&gt;</span></pre>

	<p>
		يحتوى الشكل على 4 مسارات مغلقة: الإطار الخارجي للوجه، الوجه، الفم، العين اليمنى، العين اليسرى. <br>
		لاحظ أنني قمت باستدعاء الدَّالة <span style="font-family:courier new,courier,monospace;">()beginPath</span> أربع مرات ولم أكن بحاجة لاستدعاء الدَّالة <span style="font-family:courier new,courier,monospace;">()closePath</span> عندما رسمت الإطار بالرغم من أنه stroke وذلك بسبب تقاطع نقطة النهاية مع البداية. 
	</p>

	<p>
		أيضًا عند رسم الأشكال solid لم أحتج لاستدعاء الدَّالة <span style="font-family: 'courier new', courier, monospace; line-height: 24.8889px;">()closePath</span> وذلك لأن الدَّالة <span style="font-family:courier new,courier,monospace;">()fill</span> تقوم بإغلاق المسار بشكل تلقائي لتلوينه.
	</p>
</div>

<div id="wmd-preview-section-33">
	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f2352c05__4png.png.325f0084c4fcbcf742eb3e13682e1a93.png"><img alt="565c4f2354993__4png.thumb.png.32732e7a2a" class="ipsImage ipsImage_thumbnailed" data-fileid="8224" src="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f2354993__4png.thumb.png.32732e7a2a24dffd6ea074d400b000d6.png"></a>
	</p>
</div>

<div id="wmd-preview-section-34">
	<h2 id="الخطوط-lines">
		الخطوط Lines
	</h2>

	<p>
		تُستخدم الدَّالة <span style="font-family:courier new,courier,monospace;">()lineTo</span> لرسم خطوط مستقيمة بحيث ترسم الخط من النُّقطة الحالية إلى نقطة محددة بـ (x, y).
	</p>

	<p>
		النقطة الحالية تتعلق بآخر مسار تم رسمه (أي أن النُّقطة الأخيرة لرسم المسار الأول هي نقطة بداية رسم المسار الثاني)
	</p>
</div>

<div id="wmd-preview-section-35">
	<p>
		يمكنك تغيير النُّقطة الحالية عبر استدعاء الدَّالة<span style="font-family:courier new,courier,monospace;"> ()moveTo</span> كما شرحنا في المثال السابق.
	</p>

	<p>
		لنقم بعمل مثال آخر لرسم مثلَّثين أحدهما solid والآخر stroke باستخدام الدالتين <span style="font-family:courier new,courier,monospace;">()lineTo</span> و<span style="font-family:courier new,courier,monospace;"> ()moveTo</span> واستدعاء الدَّالة <span style="font-family:courier new,courier,monospace;">()lineTo</span> مرتين لكل عملية رسم مثلَّث كما في السكربت التالي:
	</p>

	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4">
<span class="tag">&lt;script&gt;</span><span class="pln"> 
</span><span class="kwd">function</span><span class="pln"> draw</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
  </span><span class="kwd">var</span><span class="pln"> canvas </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'canvas'</span><span class="pun">);</span><span class="pln"> 
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">canvas</span><span class="pun">.</span><span class="pln">getContext</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
    </span><span class="kwd">var</span><span class="pln"> ctx </span><span class="pun">=</span><span class="pln"> canvas</span><span class="pun">.</span><span class="pln">getContext</span><span class="pun">(</span><span class="str">'2d'</span><span class="pun">);</span><span class="pln"> 

    </span><span class="com">// Filled triangle </span><span class="pln">
    ctx</span><span class="pun">.</span><span class="pln">beginPath</span><span class="pun">();</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">moveTo</span><span class="pun">(</span><span class="lit">100</span><span class="pun">,</span><span class="pln"> </span><span class="lit">100</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">lineTo</span><span class="pun">(</span><span class="lit">180</span><span class="pun">,</span><span class="pln"> </span><span class="lit">100</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">lineTo</span><span class="pun">(</span><span class="lit">100</span><span class="pun">,</span><span class="pln"> </span><span class="lit">180</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">fill</span><span class="pun">();</span><span class="pln"> 

    </span><span class="com">// Stroked triangle </span><span class="pln">
    ctx</span><span class="pun">.</span><span class="pln">beginPath</span><span class="pun">();</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">moveTo</span><span class="pun">(</span><span class="lit">125</span><span class="pun">,</span><span class="pln"> </span><span class="lit">125</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">lineTo</span><span class="pun">(</span><span class="lit">125</span><span class="pun">,</span><span class="pln"> </span><span class="lit">45</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">lineTo</span><span class="pun">(</span><span class="lit">45</span><span class="pun">,</span><span class="pln"> </span><span class="lit">125</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">closePath</span><span class="pun">();</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">stroke</span><span class="pun">();</span><span class="pln"> 
  </span><span class="pun">}</span><span class="pln"> 
</span><span class="pun">}</span><span class="pln"> 
</span><span class="tag">&lt;/script&gt;</span></pre>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f248ecf3__5.png.f611f0dc69e924374895b5f4da067eac.png"><img alt="565c4f249094e__5.thumb.png.67badbd92a461" class="ipsImage ipsImage_thumbnailed" data-fileid="8225" src="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f249094e__5.thumb.png.67badbd92a46156afcb1d077da322fd6.png"></a>
	</p>

	<p>
		قمت باستدعاء الدَّالة ()beginPath عند البدء في رسم الشكل ثم استدعاء الدَّالة <span style="font-family:courier new,courier,monospace;">()moveTo</span> للانتقال لنقطة بداية الرَّسم. ثم بعد ذلك استدعاء الدَّالة <span style="font-family:courier new,courier,monospace;">()LineTo</span> مرّتين لرسم المثلَّث بالإحداثيات المناسبة.
	</p>
</div>

<div id="wmd-preview-section-36">
	<p>
		الآن استدعاء الدَّالة <span style="font-family:courier new,courier,monospace;">()closePath</span> عند الانتهاء من رسم المثلَّث من نوع storke لإغلاق المسار لأنه في حال عدم استدعاء هذه الدَّالة سيقوم برسم خطين فقط وليس مثلَّثا كاملًا.
	</p>
</div>

<div id="wmd-preview-section-37">
	<h2 id="الأقواس-arcs">
		الأقواس Arcs
	</h2>

	<p>
		يتم رسم الأقواس باستخدام الدالتين <span style="font-family:courier new,courier,monospace;">()arc</span> أو <span style="font-family:courier new,courier,monospace;">()arcTo.</span>
	</p>

	<p>
		تقوم الدالة <font face="courier new, courier, monospace"><span style="font-family:courier new,courier,monospace;">(</span></font><span style="font-family:courier new,courier,monospace;"><span style="line-height: 1.6;">arc(x, y, radius, startAngle, endAngle, anticlockwise بر</span></span>سم قوس عند النُّقطة (x, y) بمقدار القطر radius r ببداية الزَّاوية startAngle وانتهاءً بالزَّاوية endAngle وبالاتجاه anticlockwise (القيمة الافتراضية تكون مع اتجاه عقارب الساعة clockwise).
	</p>

	<p>
		تقوم الدالة <span style="font-family:courier new,courier,monospace;">(</span><span style="line-height: 1.6;"><span style="font-family:courier new,courier,monospace;">arcTo(x1, y1, x2, y2, radius</span> </span>برسم قوس بمجموعة نقاط وقطر radius يتصل بالنُّقطة السابقة بواسطة خط مستقيم. 
	</p>

	<p>
		إنَّ الدَّالة <span style="font-family:courier new,courier,monospace;">()arcTo</span> تأخذ 5 معاملات arguments: 
	</p>

	<ul><li>
			(x, y) وهما إحداثيي مركز الدائرة التي سيرسم عندها القوس
		</li>
		<li>
			القطر raduis هو قطر الدائرة
		</li>
		<li>
			المعاملان startAngle و endAngle يُحدّدان بداية ونهاية نقاط القوس بالراديان radians على طول قوس الدائرة حيث أنها تقاس من المحور x
		</li>
		<li>
			المعامل anticlockwise هو متغير منطقي Boolean عندما يأخذ القيمة true سيتم رسم القوس عكس اتجاه عقارب الساعة وإلا سيتم رسم القوس باتجاه عقارب الساعة. 
		</li>
	</ul><p>
		<strong>ملاحظة:</strong> الزَّوايا في الدَّالة <span style="font-family:courier new,courier,monospace;">()arc</span> تقاس بالراديان radians وليس بالدّرجات، للتحويل من الدّرجات للراديان يمكنك استخدام السكربت:
	</p>

	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4">
<span class="pln">radians </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">PI</span><span class="pun">/</span><span class="lit">180</span><span class="pun">)*</span><span class="pln">degrees</span></pre>

	<p>
		سأقوم بعرض مثال يشرح طريقة رسم مجموعة من 12 قوسًا بزوايا مختلفة، حيث ستُعرض الأقواس على شكل صفوف (أسطر وأعمدة) في كل صف ثلاث أقواس.
	</p>
</div>

<div id="wmd-preview-section-40">
	<p>
		سيتم إنشاء حلقتي تكرار وتطبيقهما على أسطر وأعمدة الأقواس.
	</p>

	<p>
		لكل مسار قوس سيتم استدعاء <span style="font-family:courier new,courier,monospace;">()beginPath</span> في السكربت لإنشاء مسار جديد في كل مرّة لرّسم شكل جديد.
	</p>

	<p>
		قمت بتخزين كل معامل للدالة <span style="font-family:courier new,courier,monospace;">arc</span> ضمن متغير لتسهيل استخدامها عند استدعاء الدَّالة.
	</p>

	<p>
		القطر radius وزاوية البداية startAngle هما ثوابت. أمّا زاوية النّهاية endAngle تبدأ من 180 درجة (نصف دائرة) في العمود الأول. وتزداد بمقدار 90 درجة لتصل إلى دائرة كاملة في العمود الأخير.
	</p>

	<p>
		في السّطر الأوّل والثّالث سيتم رسم الأقواس باتجاه عقارب الساعة، وفي السّطر الثّاني والرّابع سيتم رسم الأقواس عكس اتجاه عقارب الساعة.
	</p>

	<p>
		أخيرًا الشرط if سيقوم بعرض أقواس مُفرغة Stroke في الجزء العلوي من الصّفوف وأقواس ذات مساحة لونية solid في الجزء السُّفلي من الصّفوف. سنكون بحاجة إلى canvas بقياسات 150*200.
	</p>

	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4">
<span class="kwd">function</span><span class="pln"> draw</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
  </span><span class="kwd">var</span><span class="pln"> canvas </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(‘</span><span class="pln">canvas</span><span class="pun">’);</span><span class="pln"> 
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">canvas</span><span class="pun">.</span><span class="pln">getContext</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
    </span><span class="kwd">var</span><span class="pln"> ctx </span><span class="pun">=</span><span class="pln"> canvas</span><span class="pun">.</span><span class="pln">getContext</span><span class="pun">(‘</span><span class="lit">2d</span><span class="pun">’);</span><span class="pln">
    </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">var</span><span class="pln"> i </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> i </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">4</span><span class="pun">;</span><span class="pln"> i</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
      </span><span class="kwd">for</span><span class="pln"> </span><span class="pun">(</span><span class="kwd">var</span><span class="pln"> j </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> j </span><span class="pun">&lt;</span><span class="pln"> </span><span class="lit">3</span><span class="pun">;</span><span class="pln"> j</span><span class="pun">++)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
        ctx</span><span class="pun">.</span><span class="pln">beginPath</span><span class="pun">();</span><span class="pln"> 
        </span><span class="kwd">var</span><span class="pln"> x </span><span class="pun">=</span><span class="pln"> </span><span class="lit">25</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> j </span><span class="pun">*</span><span class="pln"> </span><span class="lit">50</span><span class="pun">;</span><span class="pln"> 
        </span><span class="kwd">var</span><span class="pln"> y </span><span class="pun">=</span><span class="pln"> </span><span class="lit">25</span><span class="pln"> </span><span class="pun">+</span><span class="pln"> i </span><span class="pun">*</span><span class="pln"> </span><span class="lit">50</span><span class="pun">;</span><span class="pln"> 
        </span><span class="kwd">var</span><span class="pln"> radius </span><span class="pun">=</span><span class="pln"> </span><span class="lit">20</span><span class="pun">;</span><span class="pln"> 
        </span><span class="kwd">var</span><span class="pln"> startAngle </span><span class="pun">=</span><span class="pln"> </span><span class="lit">0</span><span class="pun">;</span><span class="pln"> 
        </span><span class="kwd">var</span><span class="pln"> endAngle </span><span class="pun">=</span><span class="pln"> </span><span class="typ">Math</span><span class="pun">.</span><span class="pln">PI </span><span class="pun">+</span><span class="pln"> </span><span class="pun">(</span><span class="typ">Math</span><span class="pun">.</span><span class="pln">PI </span><span class="pun">*</span><span class="pln"> j</span><span class="pun">)</span><span class="pln"> </span><span class="pun">/</span><span class="pln"> </span><span class="lit">2</span><span class="pun">;</span><span class="pln"> 
        </span><span class="kwd">var</span><span class="pln"> anticlockwise </span><span class="pun">=</span><span class="pln"> i </span><span class="pun">%</span><span class="pln"> </span><span class="lit">2</span><span class="pln"> </span><span class="pun">==</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="pun">?</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln"> 
        ctx</span><span class="pun">.</span><span class="pln">arc</span><span class="pun">(</span><span class="pln">x</span><span class="pun">,</span><span class="pln"> y</span><span class="pun">,</span><span class="pln"> radius</span><span class="pun">,</span><span class="pln"> startAngle</span><span class="pun">,</span><span class="pln"> endAngle</span><span class="pun">,</span><span class="pln"> anticlockwise</span><span class="pun">);</span><span class="pln"> 

        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">i </span><span class="pun">&gt;</span><span class="pln"> </span><span class="lit">1</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> ctx</span><span class="pun">.</span><span class="pln">fill</span><span class="pun">();</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> ctx</span><span class="pun">.</span><span class="pln">stroke</span><span class="pun">();</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> 
      </span><span class="pun">}</span><span class="pln"> 
    </span><span class="pun">}</span><span class="pln"> 
  </span><span class="pun">}</span><span class="pln"> 
</span><span class="pun">}</span></pre>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f2d88761__6.png.29c66e3a04f9456f8aa3da24dbde072a.png"><img alt="565c4f2d8adfe__6.thumb.png.203eda53b6f6e" class="ipsImage ipsImage_thumbnailed" data-fileid="8226" src="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f2d8adfe__6.thumb.png.203eda53b6f6e5285ba6b808b0d3f7c0.png"></a>
	</p>
</div>

<div id="wmd-preview-section-41">
	<h2 id="المنحنيات-التكعيبية-والتربيعية-cubic-and-quadratic-curves">
		المنحنيات التكعيبية والتربيعية Cubic and Quadratic Curves
	</h2>

	<p>
		تخيّل أنّك تريد إنشاء قوس مائل أو قوس بقمة حادة أو أي نوع من الأقواس المعقدة، توفّر لك الدَّالة <span style="font-family:courier new,courier,monospace;">()quadraticCurveTo</span> إمكانيّة رسم أقواس ومنحنيات تربيعية <a href="http://ar.wikipedia.org/wiki/%D9%85%D9%86%D8%AD%D9%86%D9%89_%D8%A8%D9%8A%D8%B2%D9%8A%D9%87#.D9.85.D9.86.D8.AD.D9.86.D9.89_.D8.A8.D9.8A.D8.B2.D9.8A.D9.87_.D9.85.D9.86_.D8.A7.D9.84.D8.AF.D8.B1.D8.AC.D8.A9_.D8.A7.D9.84.D8.B1.D8.A7.D8.A8.D8.B9.D8.A9" rel="external nofollow">Quadratic</a> Curves والدَّالة <span style="font-family:courier new,courier,monospace;">()bezierCurveTo</span> تقوم برسم أقواس أو منحنيات تكعيبية cubic أو ما يعرف بـ<a href="http://ar.wikipedia.org/wiki/%D9%85%D9%86%D8%AD%D9%86%D9%89_%D8%A8%D9%8A%D8%B2%D9%8A%D9%87" rel="external nofollow">Bézier</a> Curves منحنيات بيزيير. 
	</p>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_11/7_(1).jpg.6ace454ad5bed5bd84f3777c5b449bbf.jpg"><img alt="7_(1).thumb.jpg.56325aab1e1bf74ad4b20a15" class="ipsImage ipsImage_thumbnailed" data-fileid="8227" src="https://academy.hsoub.com/uploads/monthly_2015_11/7_(1).thumb.jpg.56325aab1e1bf74ad4b20a158b9b49d0.jpg"></a>
	</p>
</div>

<div id="wmd-preview-section-42">
	<h3 id="1-رسم-منحني-تربيعي">
		1- رسم منحني تربيعي
	</h3>
</div>

<div id="wmd-preview-section-43">
	تقوم الدالة <span style="font-family:courier new,courier,monospace;">(quadraticCurveTo(cp1x, cp1y, x, y</span> بر<span style="line-height: 1.6;">سم منحني بيزيير </span><a href="http://ar.wikipedia.org/wiki/%D9%85%D9%86%D8%AD%D9%86%D9%89_%D8%A8%D9%8A%D8%B2%D9%8A%D9%87" rel="external nofollow" style="line-height: 1.6;">Bézier</a><span style="line-height: 1.6;"> تربيعي من النُّقطة الحاليّة إلى نقطة معيّنة محددة بـ (x, y) باستخدام نقطة تحكم control point المحدّدة بـ cp1x و cp1y.</span>

	<p>
		تقوم الدَّالة <span style="font-family:courier new,courier,monospace;">(bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y</span> برسم منحني بيزيير Bézier تكعيبي cubic باستخدام النّقاط المتحكّمة عن طريق (cp1x, cp1y) و (cp2x, cp2y).
	</p>

	<p>
		الصورة التّالية توضّح الفرق بين المنحنيين <a href="http://ar.wikipedia.org/wiki/%D9%85%D9%86%D8%AD%D9%86%D9%89_%D8%A8%D9%8A%D8%B2%D9%8A%D9%87#.D9.85.D9.86.D8.AD.D9.86.D9.89_.D8.A8.D9.8A.D8.B2.D9.8A.D9.87_.D9.85.D9.86_.D8.A7.D9.84.D8.AF.D8.B1.D8.AC.D8.A9_.D8.A7.D9.84.D8.B1.D8.A7.D8.A8.D8.B9.D8.A9" rel="external nofollow">Quadratic</a> و cubic:
	</p>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f2f8e038__8.png.41db2f8c4e48b9f2b153abb9a489b590.png"><img alt="565c4f2f906dd__8.thumb.png.4630b6d399ea2" class="ipsImage ipsImage_thumbnailed" data-fileid="8228" src="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f2f906dd__8.thumb.png.4630b6d399ea28bc725e8bcdc52326b3.png"></a>
	</p>

	<p>
		لاحظ أن منحني <a href="http://ar.wikipedia.org/wiki/%D9%85%D9%86%D8%AD%D9%86%D9%89_%D8%A8%D9%8A%D8%B2%D9%8A%D9%87" rel="external nofollow">Bézier</a> من الدّرجة الرّابعة لديه نقطة بداية ونقطة نهاية (النقاط الزرقاء) ونقطة تحكم واحدة (النُّقطة الحمراء) في حين أن منحني <a href="http://ar.wikipedia.org/wiki/%D9%85%D9%86%D8%AD%D9%86%D9%89_%D8%A8%D9%8A%D8%B2%D9%8A%D9%87" rel="external nofollow">Bézier</a> من الدرجة الثالثة لديه نقطتي تحكم. 
	</p>

	<p>
		المعاملين x و y في كلا الدّالتين هما إحداثيات نقطة النّهاية. المعاملين cp1x و cp1y هما إحداثيات نقطة التحكم الأولى، المعاملين cp2x و cp2y هما إحداثيات نقطة التحكم الثانية. 
	</p>

	<p>
		لنأخذ مثالًا عن كيفية إنشاء منحني Bézier تربيعي سيكون المثال مسلي بعض الشيء إذ أنني سأقوم بإنشاء بالون محادثة speech balloon:
	</p>

	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4">
<span class="kwd">function</span><span class="pln"> draw</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
  </span><span class="kwd">var</span><span class="pln"> canvas </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'canvas'</span><span class="pun">);</span><span class="pln"> 
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">canvas</span><span class="pun">.</span><span class="pln">getContext</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
    </span><span class="kwd">var</span><span class="pln"> ctx </span><span class="pun">=</span><span class="pln"> canvas</span><span class="pun">.</span><span class="pln">getContext</span><span class="pun">(</span><span class="str">'2d'</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">beginPath</span><span class="pun">();</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">moveTo</span><span class="pun">(</span><span class="lit">75</span><span class="pun">,</span><span class="pln"> </span><span class="lit">25</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">quadraticCurveTo</span><span class="pun">(</span><span class="lit">25</span><span class="pun">,</span><span class="pln"> </span><span class="lit">25</span><span class="pun">,</span><span class="pln"> </span><span class="lit">25</span><span class="pun">,</span><span class="pln"> </span><span class="lit">62.5</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">quadraticCurveTo</span><span class="pun">(</span><span class="lit">25</span><span class="pun">,</span><span class="pln"> </span><span class="lit">100</span><span class="pun">,</span><span class="pln"> </span><span class="lit">50</span><span class="pun">,</span><span class="pln"> </span><span class="lit">100</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">quadraticCurveTo</span><span class="pun">(</span><span class="lit">50</span><span class="pun">,</span><span class="pln"> </span><span class="lit">120</span><span class="pun">,</span><span class="pln"> </span><span class="lit">30</span><span class="pun">,</span><span class="pln"> </span><span class="lit">125</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">quadraticCurveTo</span><span class="pun">(</span><span class="lit">60</span><span class="pun">,</span><span class="pln"> </span><span class="lit">120</span><span class="pun">,</span><span class="pln"> </span><span class="lit">65</span><span class="pun">,</span><span class="pln"> </span><span class="lit">100</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">quadraticCurveTo</span><span class="pun">(</span><span class="lit">125</span><span class="pun">,</span><span class="pln"> </span><span class="lit">100</span><span class="pun">,</span><span class="pln"> </span><span class="lit">125</span><span class="pun">,</span><span class="pln"> </span><span class="lit">62.5</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">quadraticCurveTo</span><span class="pun">(</span><span class="lit">125</span><span class="pun">,</span><span class="pln"> </span><span class="lit">25</span><span class="pun">,</span><span class="pln"> </span><span class="lit">75</span><span class="pun">,</span><span class="pln"> </span><span class="lit">25</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">stroke</span><span class="pun">();</span><span class="pln"> 
  </span><span class="pun">}</span><span class="pln"> 
</span><span class="pun">}</span></pre>

	<p>
		تقوم الدَّالة <span style="font-family:courier new,courier,monospace;">()quadraticCurveTo</span> برسم منحني بالإحداثيات ونقطة التحكم المناسبة عند استدعائها بالقيم وبالترتيب أعلاه: 
	</p>
</div>

<div id="wmd-preview-section-44">
	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f5131410__curve_1.png.b379e2535ab8dd047a36d211cd9c1d76.png"><img alt="565c4f5132a76__curve_1.thumb.png.cbb1127" class="ipsImage ipsImage_thumbnailed" data-fileid="8234" src="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f5132a76__curve_1.thumb.png.cbb1127b02408760682284b7874d1d99.png"></a>
	</p>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f527e534__curve_2.png.8ea6fba9d813f39a9ca01b103df41a33.png"><img alt="565c4f527fd60__curve_2.thumb.png.62620b2" class="ipsImage ipsImage_thumbnailed" data-fileid="8235" src="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f527fd60__curve_2.thumb.png.62620b25655ddf54d50119fb1865c0c6.png"></a>
	</p>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f5355ed4__curve_3.png.711bd26eaddda614d85b1b68366e63a0.png"><img alt="565c4f5357e5b__curve_3.thumb.png.1e65c5c" class="ipsImage ipsImage_thumbnailed" data-fileid="8236" src="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f5357e5b__curve_3.thumb.png.1e65c5cba2e4577afc17b927b7fe832b.png"></a>
	</p>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f541fa9a__curve_4.png.ca15305643cc0917e20bbfe272a9451c.png"><img alt="565c4f54212d5__curve_4.thumb.png.2dd95e7" class="ipsImage ipsImage_thumbnailed" data-fileid="8237" src="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f54212d5__curve_4.thumb.png.2dd95e762119e1f6b569a33959fd6e22.png"></a>
	</p>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f55dfb8e__curve_5.png.60227c64e41d9508ee3e2ce1d71fcb2c.png"><img alt="565c4f55e1c33__curve_5.thumb.png.ed8ae5c" class="ipsImage ipsImage_thumbnailed" data-fileid="8238" src="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f55e1c33__curve_5.thumb.png.ed8ae5c7df00b3ab81f283b614bfc684.png"></a>
	</p>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f5a13889__curve_6.png.08854f52ed7f4d143f904076ec6c3f82.png"><img alt="565c4f5a1584e__curve_6.thumb.png.9aa4c2f" class="ipsImage ipsImage_thumbnailed" data-fileid="8239" src="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f5a1584e__curve_6.thumb.png.9aa4c2fdc41767fb5c438fe7444a8183.png"></a>
	</p>
</div>

<div id="wmd-preview-section-45">
	<h3 id="2-رسم-منحي-تكعيبي">
		2- رسم منحي تكعيبي
	</h3>

	<p>
		في المثال التالي شرح استخدام الدَّالة <span style="font-family:courier new,courier,monospace;">(</span><span style="line-height: 1.6;"><span style="font-family:courier new,courier,monospace;">bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y</span> </span>لرسم منحنيات من الدرجة الثالثة. 
	</p>

	<p>
		تفيدنا هذه الدَّالة في رسم أشكال أكثر تعقيدًا لنأخذ مثلًا شكل القلب:
	</p>

	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4">
<span class="kwd">function</span><span class="pln"> draw</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
  </span><span class="kwd">var</span><span class="pln"> canvas </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(‘</span><span class="pln">canvas</span><span class="pun">’);</span><span class="pln"> 
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">canvas</span><span class="pun">.</span><span class="pln">getContext</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
    </span><span class="kwd">var</span><span class="pln"> ctx </span><span class="pun">=</span><span class="pln"> canvas</span><span class="pun">.</span><span class="pln">getContext</span><span class="pun">(‘</span><span class="lit">2d</span><span class="pun">’);</span><span class="pln">
    ctx</span><span class="pun">.</span><span class="pln">beginPath</span><span class="pun">();</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">fillStyle </span><span class="pun">=</span><span class="pln"> </span><span class="str">"rgb(200,0,0)"</span><span class="pun">;</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">moveTo</span><span class="pun">(</span><span class="lit">75</span><span class="pun">,</span><span class="pln"> </span><span class="lit">40</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">bezierCurveTo</span><span class="pun">(</span><span class="lit">75</span><span class="pun">,</span><span class="pln"> </span><span class="lit">37</span><span class="pun">,</span><span class="pln"> </span><span class="lit">70</span><span class="pun">,</span><span class="pln"> </span><span class="lit">25</span><span class="pun">,</span><span class="pln"> </span><span class="lit">50</span><span class="pun">,</span><span class="pln"> </span><span class="lit">25</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">bezierCurveTo</span><span class="pun">(</span><span class="lit">20</span><span class="pun">,</span><span class="pln"> </span><span class="lit">25</span><span class="pun">,</span><span class="pln"> </span><span class="lit">20</span><span class="pun">,</span><span class="pln"> </span><span class="lit">62.5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">20</span><span class="pun">,</span><span class="pln"> </span><span class="lit">62.5</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">bezierCurveTo</span><span class="pun">(</span><span class="lit">20</span><span class="pun">,</span><span class="pln"> </span><span class="lit">80</span><span class="pun">,</span><span class="pln"> </span><span class="lit">40</span><span class="pun">,</span><span class="pln"> </span><span class="lit">102</span><span class="pun">,</span><span class="pln"> </span><span class="lit">75</span><span class="pun">,</span><span class="pln"> </span><span class="lit">120</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">bezierCurveTo</span><span class="pun">(</span><span class="lit">110</span><span class="pun">,</span><span class="pln"> </span><span class="lit">102</span><span class="pun">,</span><span class="pln"> </span><span class="lit">130</span><span class="pun">,</span><span class="pln"> </span><span class="lit">80</span><span class="pun">,</span><span class="pln"> </span><span class="lit">130</span><span class="pun">,</span><span class="pln"> </span><span class="lit">62.5</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">bezierCurveTo</span><span class="pun">(</span><span class="lit">130</span><span class="pun">,</span><span class="pln"> </span><span class="lit">62.5</span><span class="pun">,</span><span class="pln"> </span><span class="lit">130</span><span class="pun">,</span><span class="pln"> </span><span class="lit">25</span><span class="pun">,</span><span class="pln"> </span><span class="lit">100</span><span class="pun">,</span><span class="pln"> </span><span class="lit">25</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">bezierCurveTo</span><span class="pun">(</span><span class="lit">85</span><span class="pun">,</span><span class="pln"> </span><span class="lit">25</span><span class="pun">,</span><span class="pln"> </span><span class="lit">75</span><span class="pun">,</span><span class="pln"> </span><span class="lit">37</span><span class="pun">,</span><span class="pln"> </span><span class="lit">75</span><span class="pun">,</span><span class="pln"> </span><span class="lit">40</span><span class="pun">);</span><span class="pln"> 
    ctx</span><span class="pun">.</span><span class="pln">fill</span><span class="pun">();</span><span class="pln"> 
  </span><span class="pun">}</span><span class="pln"> 
</span><span class="pun">}</span></pre>

	<p>
		ينتج عن استدعاء الدَّالة<span style="font-family:courier new,courier,monospace;"> (bezierCurveTo(cp1x, cp1y, cp2x, cp2y, x, y</span> بالقيم وبالترتيب أعلاه الشكل:
	</p>
</div>

<div id="wmd-preview-section-46">
	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f38cda8c__cubic_1.png.f8fe4f9eb14f5710abbd683f4722ae59.png"><img alt="565c4f38cfac9__cubic_1.thumb.png.ec850cb" class="ipsImage ipsImage_thumbnailed" data-fileid="8229" src="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f38cfac9__cubic_1.thumb.png.ec850cbf4035bd9ef9509b695c325870.png"></a>
	</p>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f3a2ea1f__cubic_2.png.c94e318a1683f5e19bf99f295ac1b618.png"><img alt="565c4f3a30864__cubic_2.thumb.png.1807259" class="ipsImage ipsImage_thumbnailed" data-fileid="8230" src="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f3a30864__cubic_2.thumb.png.1807259ac0281c10ee71859c3fe18dca.png"></a>
	</p>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f3b4223f__cubic_3.png.7136a5ae6287ec2de8b88cfa5f6ce788.png"><img alt="565c4f3b44307__cubic_3.thumb.png.90a40e1" class="ipsImage ipsImage_thumbnailed" data-fileid="8231" src="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f3b44307__cubic_3.thumb.png.90a40e18db08d56e93149da3602ddfe7.png"></a>
	</p>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f3bea60e__cubic_4.png.1a9f0c89823c7153976f3a7416dba497.png"><img alt="565c4f3bec5be__cubic_4.thumb.png.529c778" class="ipsImage ipsImage_thumbnailed" data-fileid="8232" src="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f3bec5be__cubic_4.thumb.png.529c7787f95ca13659a7dc20b547b58c.png"></a>
	</p>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f3cdfd0f__cubic_5.png.bb384a1200570eea3140c7627ebff7e5.png"><img alt="565c4f3ce19b4__cubic_5.thumb.png.f83663d" class="ipsImage ipsImage_thumbnailed" data-fileid="8233" src="https://academy.hsoub.com/uploads/monthly_2015_11/565c4f3ce19b4__cubic_5.thumb.png.f83663d0c3e3b1f869e8157bbaafe335.png"></a>
	</p>

	<p>
		ها قد أنهينا تفاصيل إنشاء ورسم أشكال بطرق مختلفة على عنصر اللوحة Cancas، بوصولك إلى هنا تكون قد كونت معرفة ممتازة عن كيفية رسم مستطيلات، مثلثات، خطوط، أقواس ومنحنيات وأيضًا التعامل مع المسارات في Canvas. 
	</p>

	<p>
		سنقوم في الدرس المقبل بـ<a href="https://academy.hsoub.com/programming/javascript/%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%A7%D9%84%D8%AA%D8%B5%D8%A7%D9%85%D9%8A%D9%85%D8%8C-%D8%A7%D9%84%D8%A3%D9%84%D9%88%D8%A7%D9%86-%D9%88%D8%A7%D9%84%D8%AE%D8%B7%D9%88%D8%B7-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-canvas-%D9%81%D9%8A-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r239/">إنشاء شكل رسومي أكثر احترافية</a> باستخدام كل تلك الأدوات معًا.
	</p>

	<p>
		<a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API" rel="external nofollow">المصادر</a>
	</p>
</div>
]]></description><guid isPermaLink="false">209</guid><pubDate>Mon, 30 Nov 2015 14:41:00 +0000</pubDate></item><item><title>&#x645;&#x62F;&#x62E;&#x644; &#x625;&#x644;&#x649; &#x62A;&#x637;&#x648;&#x64A;&#x631; &#x62A;&#x637;&#x628;&#x64A;&#x642;&#x627;&#x62A; &#x633;&#x637;&#x62D; &#x645;&#x643;&#x62A;&#x628; &#x645;&#x628;&#x646;&#x64A;&#x629; &#x639;&#x644;&#x649; Node.js &#x648; NW.js</title><link>https://academy.hsoub.com/programming/javascript/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%B3%D8%B7%D8%AD-%D9%85%D9%83%D8%AA%D8%A8-%D9%85%D8%A8%D9%86%D9%8A%D8%A9-%D8%B9%D9%84%D9%89-nodejs-%D9%88-nwjs-r208/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_11/nwjs-init.png.6f01fa6155c33c6c5d9864c080ccf342.png" /></p>
<div id="wmd-preview-section-21">
	<p id="مقدمة">
		سنتعرّف في هذا الدّرس على أداة <strong>nw</strong> (سابقًا node-webkit) المُخصّصة ل<a href="https://academy.hsoub.com/programming/general/%D8%A8%D8%B1%D9%85%D8%AC%D8%A9-%D8%AA%D8%B7%D8%A8%D9%8A%D9%82%D8%A7%D8%AA-%D8%B3%D8%B7%D8%AD-%D8%A7%D9%84%D9%85%D9%83%D8%AA%D8%A8/" rel="">تطوير تطبيقات سطح المكتب</a> العابرة للمنصات؛ باستخدام مُتصفّح كروميوم [Chromium  [1 و <strong>node.js</strong>. حيث أصبح بالإمكان استخدام تقنيات الوِب الحديثة لتطوير برمجيات قادرة على الاستفادة من موارد النظام؛ كالتحكّّم بالملفات، استعمال قواعد البيانات وغيرها من الأمور. في هذا الدّرس سنتعلّم كيفية كتابة تطبيق لسطح المكتب باستخدام nw لتشغيل ملفّات الفيديو. لنبدأ.
	</p>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_11/nwjs-init.png.11101dac785a66085066b6fe724c882e.png" data-fileid="8158" data-fileext="png" rel=""><img alt="nwjs-init.thumb.png.60a6d9fdd852fef1ff0c" class="ipsImage ipsImage_thumbnailed" data-fileid="8158" src="https://academy.hsoub.com/uploads/monthly_2015_11/nwjs-init.thumb.png.60a6d9fdd852fef1ff0cec0ab5c41b79.png"></a>
	</p>
</div>

<div id="wmd-preview-section-23">
	<h2 id="تثبيت-nodejs">
		تثبيت node.js
	</h2>

	<p>
		إذ كنت تَستخدم نظام التشغيل Windows أو Mac OS عندها استعمل معالج <a href="https://nodejs.org/en/#download" rel="external nofollow">التثبيت</a> الرسمي، أما في حال عملك على نظام لينكس فقم بتثبيتها من خلال <a href="https://nodejs.org/en/download/package-manager/" rel="external nofollow">مدير الحزم</a>.
	</p>
</div>

<div id="wmd-preview-section-24">
	<h2 id="تثبيت-nw">
		تثبيت nw
	</h2>

	<p>
		بعد تركيب node.js من خلال مدير حزم node.js نحتاج إلى تركيب <span style="font-family:courier new,courier,monospace;">nw</span>، للقيام بذلك نفّذ ما يلي من خلال الطرفية: 
	</p>

	<pre class="html ipsCode prettyprint prettyprinted" data-pbcklang="html" data-pbcktabsize="4" style=""><span class="pln">npm install nw </span><span class="pun">-</span><span class="pln">g</span></pre>
</div>

<div id="wmd-preview-section-25">
	<h2 id="أهلا-بالعالم">
		أهلا بالعالم
	</h2>

	<p>
		أنشئ مُجلدًا مُخصصًا لمشروعنا الأول باسم <span style="font-family:courier new,courier,monospace;">helloworld</span> ثم أنشئ بداخله ملفّين: 
	</p>

	<pre class="html ipsCode prettyprint prettyprinted" data-pbcklang="html" data-pbcktabsize="4" style=""><span class="kwd">package</span><span class="pun">.</span><span class="pln">json</span></pre>

	<p>
		إن سبق لك التطوير باستخدام <strong>node.js</strong> فستعرف بالتأكيد أن هذا هو الملف الخاص بمعلومات و خصائص التطبيق أو الحزمة، يمكنك إنشاءه بسهولة من خلال سطر الأوامر: 
	</p>

	<pre class="html ipsCode prettyprint prettyprinted" data-pbcklang="html" data-pbcktabsize="4" style=""><span class="pln">npm init </span></pre>

	<p>
		سنضيف إلى الملفّ بعض خصائص nw (حجم النافذة و الرابط للملف الرّئيسيّ) ليصبح شكل الملف بالكامل هكذا: 
	</p>

	<pre class="html ipsCode prettyprint prettyprinted" data-pbcklang="html" data-pbcktabsize="4" style=""><span class="pun">{</span><span class="pln"> 
  </span><span class="pun">“</span><span class="pln">name</span><span class="pun">”:</span><span class="pln"> </span><span class="pun">“</span><span class="pln">helloworld</span><span class="pun">”,</span><span class="pln"> 
  </span><span class="pun">“</span><span class="pln">version</span><span class="pun">”:</span><span class="pln"> </span><span class="pun">“</span><span class="lit">1.0</span><span class="pun">.</span><span class="lit">0</span><span class="pun">”,</span><span class="pln"> 
  </span><span class="pun">“</span><span class="pln">description</span><span class="pun">”:</span><span class="pln"> </span><span class="pun">“”,</span><span class="pln"> 
  </span><span class="pun">“</span><span class="pln">main</span><span class="pun">”:</span><span class="pln"> </span><span class="pun">“</span><span class="pln">index</span><span class="pun">.</span><span class="pln">html</span><span class="pun">”,</span><span class="pln"> 
  </span><span class="pun">“</span><span class="pln">window</span><span class="pun">”:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
    </span><span class="pun">“</span><span class="pln">width</span><span class="pun">”:</span><span class="pln"> </span><span class="lit">600</span><span class="pun">,</span><span class="pln"> 
    </span><span class="pun">“</span><span class="pln">height</span><span class="pun">”:</span><span class="pln"> </span><span class="lit">400</span><span class="pln"> 
  </span><span class="pun">},</span><span class="pln"> 
  </span><span class="pun">“</span><span class="pln">scripts</span><span class="pun">”:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
    </span><span class="pun">“</span><span class="pln">test</span><span class="pun">”:</span><span class="pln"> </span><span class="pun">“</span><span class="pln">echo \”</span><span class="typ">Error</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">no</span><span class="pln"> test specified\” </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="kwd">exit</span><span class="pln"> </span><span class="lit">1</span><span class="pun">”</span><span class="pln"> 
  </span><span class="pun">},</span><span class="pln"> 
  </span><span class="pun">“</span><span class="pln">author</span><span class="pun">”:</span><span class="pln"> </span><span class="pun">“</span><span class="pln">hsoubAcademy</span><span class="pun">”,</span><span class="pln"> 
  </span><span class="pun">“</span><span class="pln">license</span><span class="pun">”:</span><span class="pln"> </span><span class="pun">“</span><span class="pln">MIT</span><span class="pun">”</span><span class="pln"> 
</span><span class="pun">}</span><span class="pln"> </span></pre>

	<h3>
		index.html
	</h3>

	<p>
		هو ملف <span style="font-family:courier new,courier,monospace;">nw</span> الرئّيسيّ الذي قمنا بتحديده من ملف الحزمة (<span style="font-family:courier new,courier,monospace;">package.json</span>)، سنُنشئ مُستند بسيط لطباعة أهلًا بالعالم.
	</p>

	<h3>
		تشغيل التطبيق
	</h3>
</div>

<div id="wmd-preview-section-26">
	<p>
		من خلال سطر الأوامر انتقل إلى ملف المشروع وشغّل <span style="font-family:courier new,courier,monospace;">nw</span>: 
	</p>

	<pre class="html ipsCode prettyprint prettyprinted" data-pbcklang="html" data-pbcktabsize="4" style=""><span class="pln">cd helloworld 
nw </span></pre>

	<p>
		يجب أن تظهر لك نافذة بحجم 600X400px وبداخلها نص "أهلًا بالعالم".
	</p>
</div>

<div id="wmd-preview-section-27">
	<h2 id="سياق-شفرة-javascript">
		سياق شفرة javascript
	</h2>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_11/nodewebkit-contexts.png.33ac2f54a519aeee744010a0d1b490fa.png" data-fileid="8150" data-fileext="png" rel=""><img alt="nodewebkit-contexts.thumb.png.1e09136f1e" class="ipsImage ipsImage_thumbnailed" data-fileid="8150" src="https://academy.hsoub.com/uploads/monthly_2015_11/nodewebkit-contexts.thumb.png.1e09136f1e7c26fd0c19af498c87f3fd.png"></a> 
	</p>

	<p>
		يوجد بـ nw سياقان لشِفرة javascript: سياق المُتصفّح وسياق node.js، عند استدعائك لملف javascript أو تشغيلك لشيفرة من خلال مستند html فإن هذه الشفرة تُمرر إلى المتصفح ليقرأها، أما عند تشغيلك لملفّ javascript من خلال خاصية<span style="font-family:courier new,courier,monospace;"> node-main </span>في ملفّ الحزمة (<span style="font-family:courier new,courier,monospace;">package.json</span>) أو استدعائه من خلال الدّالّة <span style="font-family:courier new,courier,monospace;">require</span> فإنه يُمرر إلى سياق node.js، حيث يوجد بعض الاختلافات الطفيفة بين هذين السياقين في الكتابة:
	</p>

	<h3>
		1. سياق المتصفح 
	</h3>

	<p>
		في هذا السياق تعمل الشيفرة بالأسلوب الذي تعمل به في المتصفح، المُتغيّر العام هو <span style="font-family:courier new,courier,monospace;">window</span> مثلًا، هذه الشيفرة ستعمل بشكل صحيح فقط في سياق المُتصفح: 
	</p>

	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4" style=""><span class="pln">myVar </span><span class="pun">=</span><span class="pln"> </span><span class="pun">“</span><span class="pln">test</span><span class="pun">”;</span><span class="pln"> </span><span class="com">// تعريف مُتغير بشكل عام </span><span class="pln">
alert</span><span class="pun">(</span><span class="pln">window</span><span class="pun">.</span><span class="pln">myVar</span><span class="pun">);</span><span class="pln"> </span><span class="com">// إخراج نافذة بالمتغير </span></pre>

	<p>
		ولتمرير المُتغيرات بشكل عام إلى سياق node.js يجب تعريفها كتابع للمُتغير <span style="font-family:courier new,courier,monospace;">window.global</span> مثال ليعمل مثال: 
	</p>

	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4" style=""><span class="com">// ملف window.js </span><span class="pln">
</span><span class="com">// هذا الملف يجب أن يعمل من سياق المُتصفح </span><span class="pln">
window</span><span class="pun">.</span><span class="kwd">global</span><span class="pun">.</span><span class="pln">myVar </span><span class="pun">=</span><span class="pln"> </span><span class="pun">“</span><span class="pln">test</span><span class="pun">”;</span><span class="pln"> </span><span class="com">// تعريف مُتغيّر بشكل عام إلى سياق المُتصفح </span><span class="pln">
</span><span class="kwd">require</span><span class="pun">(“</span><span class="pln">node</span><span class="pun">.</span><span class="pln">js</span><span class="pun">”);</span><span class="pln"> </span><span class="com">// استدعاء ملف node.js بداخل سياق node.js</span></pre>

	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4" style="line-height: 24.8889px;"><span class="com">// ملف node.js </span><span class="pln">
</span><span class="com">// هذا الملف يجب أن يعمل من سياق node.js </span><span class="pln">
window</span><span class="pun">.</span><span class="pln">alert</span><span class="pun">(</span><span class="pln">myVar</span><span class="pun">);</span><span class="pln"> </span><span class="com">// عرض المُتغير الّذي تم تعريفه بشكل عام من سياق المُتصفح</span></pre>

	<h3>
		2. سياق node.js 
	</h3>

	<p>
		في هذه السياق تعمل الشيفرة بأسلوب عملها باستخدام node.js، المُتغير العام هو <span style="font-family:courier new,courier,monospace;">global</span> مثال: 
	</p>

	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4" style=""><span class="pln">myVar </span><span class="pun">=</span><span class="pln"> </span><span class="pun">“</span><span class="pln">test</span><span class="pun">”;</span><span class="pln"> </span><span class="com">// تعريف مُتغير بشكل عام </span><span class="pln">
window</span><span class="pun">.</span><span class="pln">alert</span><span class="pun">(</span><span class="kwd">global</span><span class="pun">.</span><span class="pln">myVar</span><span class="pun">);</span><span class="pln"> </span><span class="com">// إخراج نافذة بالمتغير العام الّذي قمنا بتعريفه </span></pre>

	<p>
		يُمكن استخدام سياق المتصفح والتمرير إليه من خلال المُتغير <span style="font-family:courier new,courier,monospace;">window</span>.
	</p>
</div>

<div id="wmd-preview-section-28">
	<h3 id="استدعاء-الحزم-التي-كتبت-للمتصفح-بداخل-سياق-nodejs">
		استدعاء الحزم التي كتبت للمتصفح بداخل سياق node.js
	</h3>

	<p>
		عند استدعاء حزم تمت كتابتها للمُتصفح بداخل سياق node.js عن طريق الدّالّة <span style="font-family:courier new,courier,monospace;">require</span> فقد لا تعمل، حيث تحدثنا سابقًا أن المتغيّر العام في سياق node.js هو <span style="font-family:courier new,courier,monospace;">global</span> و ليس <span style="font-family:courier new,courier,monospace;">window</span> مما يسبب مشكلة إن تم استدعاء أحد توابع <span style="font-family:courier new,courier,monospace;">window</span>، عمومًا فالمثال لن يعمل في سياق node.js: 
	</p>

	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4" style=""><span class="kwd">var</span><span class="pln"> div </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(“</span><span class="pln">div</span><span class="pun">”);</span><span class="pln"> </span></pre>

	<p>
		لجعل هذه الشيفرة تعمل يجب تعريف مُتغير <span style="font-family:courier new,courier,monospace;">document</span> بشكل عام في سياق node.js: 
	</p>

	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4" style=""><span class="kwd">global</span><span class="pun">.</span><span class="pln">document </span><span class="pun">=</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">document</span><span class="pun">;</span><span class="pln"> </span></pre>

	<p>
		بشكل مبدئي سيجعل هذين السطرين أغلب الحزم تعمل: 
	</p>

	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4" style=""><span class="kwd">global</span><span class="pun">.</span><span class="pln">document </span><span class="pun">=</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">document</span><span class="pun">;</span><span class="pln"> 
</span><span class="kwd">global</span><span class="pun">.</span><span class="pln">navigator </span><span class="pun">=</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">navigator</span><span class="pun">;</span><span class="pln"> </span></pre>

	<p>
		إن كنت تبحث عن حل تلقائي لنقل جميع المُتغيرات إلى سياق node.js (قد لا يُنصح بهذا الحل بسبب حذف المُتغيرات المتطابقة في الاسم): 
	</p>

	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4" style=""><span class="kwd">var</span><span class="pln"> </span><span class="typ">Var</span><span class="pun">;</span><span class="pln"> 
</span><span class="kwd">for</span><span class="pun">(</span><span class="typ">Var</span><span class="pln"> </span><span class="kwd">in</span><span class="pln"> window</span><span class="pun">)</span><span class="pln"> 
  </span><span class="kwd">if</span><span class="pun">(</span><span class="typ">Var</span><span class="pln"> </span><span class="pun">!=</span><span class="pln"> </span><span class="pun">“</span><span class="kwd">require</span><span class="pun">”)</span><span class="pln"> 
    </span><span class="kwd">global</span><span class="pun">[</span><span class="typ">Var</span><span class="pun">]</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> window</span><span class="pun">[</span><span class="typ">Var</span><span class="pun">];</span><span class="pln"> </span></pre>

	<p>
		<strong>ملاحظة:</strong> لم ننقل مُتغير <span style="font-family:courier new,courier,monospace;">require</span> لأن التابع <span style="font-family:courier new,courier,monospace;">window.require</span> يستخدم <span style="font-family:courier new,courier,monospace;">global.require</span> في استدعاء الحزم. 
	</p>

	<p>
		لاحظ أيضًا أنه لا يمكن استدعاء حزمة <span style="font-family:courier new,courier,monospace;">nw.gui</span> الخاصة بواجهة المستخدم من خلال سياق node.js عن طريق الدّالّة <span style="font-family:courier new,courier,monospace;">require</span> فكما ذكرنا؛ التابع <span style="font-family:courier new,courier,monospace;">window.require</span> يختلف عن<span style="font-family:courier new,courier,monospace;"> global.require</span>. هذا هو النص المصدري للتابع: 
	</p>

	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4" style=""><span class="pln">window</span><span class="pun">.</span><span class="kwd">require</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">(</span><span class="pln">name</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
  </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">name </span><span class="pun">==</span><span class="pln"> </span><span class="pun">‘</span><span class="pln">nw</span><span class="pun">.</span><span class="pln">gui</span><span class="pun">’)</span><span class="pln"> 
    </span><span class="kwd">return</span><span class="pln"> nwDispatcher</span><span class="pun">.</span><span class="pln">requireNwGui</span><span class="pun">();</span><span class="pln"> 
  </span><span class="kwd">return</span><span class="pln"> </span><span class="kwd">global</span><span class="pun">.</span><span class="kwd">require</span><span class="pun">(</span><span class="pln">name</span><span class="pun">);</span><span class="pln"> 
</span><span class="pun">}</span><span class="pln"> </span></pre>

	<p>
		وكما تلاحظ إن كان اسم الحزمة node.js فإنه يستخدم هذه الدّالّة لاستدعائها: 
	</p>

	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4" style=""><span class="pln">nwDispatcher</span><span class="pun">.</span><span class="pln">requireNwGui</span><span class="pun">();</span><span class="pln"> </span></pre>

	<p>
		إذًا لاستدعائها من خلال سياق node.js استخدم الدّالّة السابقة أو استخدم <span style="font-family:courier new,courier,monospace;">window.require</span>.
	</p>
</div>

<div id="wmd-preview-section-29">
	<h2 id="إنشاء-تطبيق-لتشغيل-الفيديو">
		إنشاء تطبيق لتشغيل الفيديو
	</h2>
</div>

<div id="wmd-preview-section-30">
	<h3 id="ملفات-المشروع">
		ملفات المشروع
	</h3>

	<p>
		هذه قائمة لملفات المشروع: 
	</p>

	<blockquote class="ipsQuote" data-cite="اقتباس" data-ipsquote="">
		<div class="ipsQuote_citation">
			اقتباس
		</div>

		<div class="ipsQuote_contents ipsClearfix" data-gramm="false">
			<p style="text-align: left;">
				src/ <br>
				app.js <br>
				style.css <br>
				index.html <br>
				package.json
			</p>
		</div>
	</blockquote>
</div>

<div id="wmd-preview-section-31">
	<h3 id="ملف-الحزمةpackagejson">
		ملف الحزمة (package.json)
	</h3>

	<p>
		حجم النافذة الافتراضي هو 800x600px، الملفّ الرّئيسيّ هو <span style="font-family:courier new,courier,monospace;">index.html،</span> مبدئيًا سيكون الملف بهذا الشكل: 
	</p>

	<pre class="html ipsCode prettyprint prettyprinted" data-pbcklang="html" data-pbcktabsize="4" style=""><span class="pun">{</span><span class="pln"> 
  </span><span class="pun">“</span><span class="pln">name</span><span class="pun">”:</span><span class="pln"> </span><span class="pun">“</span><span class="pln">nw</span><span class="pun">-</span><span class="pln">video</span><span class="pun">-</span><span class="pln">player</span><span class="pun">”,</span><span class="pln"> 
  </span><span class="pun">“</span><span class="pln">version</span><span class="pun">”:</span><span class="pln"> </span><span class="pun">“</span><span class="lit">1.0</span><span class="pun">.</span><span class="lit">0</span><span class="pun">”,</span><span class="pln"> 
  </span><span class="pun">“</span><span class="pln">description</span><span class="pun">”:</span><span class="pln"> </span><span class="pun">“تطبيق</span><span class="pln"> </span><span class="pun">بسيط</span><span class="pln"> </span><span class="pun">لتشغيل</span><span class="pln"> </span><span class="pun">الفيديو”,</span><span class="pln"> 
  </span><span class="pun">“</span><span class="pln">main</span><span class="pun">”:</span><span class="pln"> </span><span class="pun">“</span><span class="pln">index</span><span class="pun">.</span><span class="pln">html</span><span class="pun">”,</span><span class="pln"> 
  </span><span class="pun">“</span><span class="pln">window</span><span class="pun">”:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
    </span><span class="pun">“</span><span class="pln">width</span><span class="pun">”:</span><span class="pln"> </span><span class="lit">800</span><span class="pun">,</span><span class="pln"> 
    </span><span class="pun">“</span><span class="pln">height</span><span class="pun">”:</span><span class="pln"> </span><span class="lit">600</span><span class="pln"> 
  </span><span class="pun">},</span><span class="pln"> 
  </span><span class="pun">“</span><span class="pln">scripts</span><span class="pun">”:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
    </span><span class="pun">“</span><span class="pln">test</span><span class="pun">”:</span><span class="pln"> </span><span class="pun">“</span><span class="pln">echo \”</span><span class="typ">Error</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">no</span><span class="pln"> test specified\” </span><span class="pun">&amp;&amp;</span><span class="pln"> </span><span class="kwd">exit</span><span class="pln"> </span><span class="lit">1</span><span class="pun">”</span><span class="pln"> 
  </span><span class="pun">},</span><span class="pln"> 
  </span><span class="pun">“</span><span class="pln">author</span><span class="pun">”:</span><span class="pln"> </span><span class="pun">“</span><span class="pln">hsoubAcademy</span><span class="pun">”,</span><span class="pln"> 
  </span><span class="pun">“</span><span class="pln">license</span><span class="pun">”:</span><span class="pln"> </span><span class="pun">“</span><span class="pln">MIT</span><span class="pun">”,</span><span class="pln"> 
  </span><span class="pun">“</span><span class="pln">dependencies</span><span class="pun">”:</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
    </span><span class="pun">“</span><span class="pln">videojs</span><span class="pun">”:</span><span class="pln"> </span><span class="pun">“^</span><span class="lit">4.12</span><span class="pun">.</span><span class="lit">15</span><span class="pun">”</span><span class="pln"> 
  </span><span class="pun">}</span><span class="pln"> 
</span><span class="pun">}</span></pre>
</div>

<div id="wmd-preview-section-32">
	<h3 id="الملف-الرئيسي-indexhtml">
		الملف الرئيسي index.html
	</h3>

	<p>
		سنكتب مستند بسيط يحتوي على زر وعنصر، نضيف المشغّل ضمنه من خلال شيفرة javascript:
	</p>

	<pre class="html ipsCode prettyprint prettyprinted" data-pbcklang="html" data-pbcktabsize="4" style=""><span class="dec">&lt;!doctype html&gt;</span><span class="pln"> 
</span><span class="tag">&lt;html&gt;</span><span class="pln"> 
  </span><span class="tag">&lt;head&gt;</span><span class="pln"> 
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">charset</span><span class="pun">=</span><span class="atv">"utf-8"</span><span class="tag">&gt;</span><span class="pln"> 
    </span><span class="tag">&lt;title&gt;</span><span class="pln">تطبيق بسيط لتشغيل الفيديو</span><span class="tag">&lt;/title&gt;</span><span class="pln"> 

    </span><span class="com">&lt;!-- ملف شفرة js الرّئيسية للتطبيق --&gt;</span><span class="pln"> 
    </span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"src/app.js"</span><span class="tag">&gt;&lt;/script&gt;</span><span class="pln"> 
  </span><span class="tag">&lt;/head&gt;</span><span class="pln"> 
  </span><span class="tag">&lt;body&gt;</span><span class="pln"> 
    </span><span class="tag">&lt;button</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"play"</span><span class="tag">&gt;</span><span class="pln">فتح</span><span class="tag">&lt;/button&gt;</span><span class="pln"> 
    </span><span class="tag">&lt;div</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"player"</span><span class="tag">&gt;&lt;/div&gt;</span><span class="pln"> 
  </span><span class="tag">&lt;/body&gt;</span><span class="pln"> 
</span><span class="tag">&lt;/html&gt;</span></pre>
</div>

<div id="wmd-preview-section-33">
	<h3 id="البدء-بالتطوير">
		نافذة فتح الملفات
	</h3>
</div>

<div id="wmd-preview-section-34">
	<p>
		لا يوجد طريقة مباشرة لفتح الملفات باستخدام نافذة النظام، لكن يُمكننا استخدام مدخل input من نوع file لفتح الملفّات: <br>
		<br>
		لكن كخلاف المتصفح للمستخدم يُتاح لنا بعض الأشياء عند التطوير بـ nw كجلب المسار الكامل الحقيقي للملفّ، ويتاح لنا فتحه من خلال javascript: 
	</p>

	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4" style=""><span class="pln">document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(“</span><span class="pln">input</span><span class="pun">”).</span><span class="pln">click</span><span class="pun">();</span><span class="pln"> </span></pre>

	<p>
		من خلال هذا سنكتب دالّة بسيطة لفتح ملفّات الفيديو وإرجاع مسار الملف مع إضافة بروتوكول file لاستخدامه من خلال المُتصفح، الدّالّة: 
	</p>

	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4" style=""><span class="com">// فتح ملف </span><span class="pln">
</span><span class="kwd">var</span><span class="pln"> openFile </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> openFile </span><span class="pun">(</span><span class="pln">callback</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
  </span><span class="kwd">var</span><span class="pln"> input </span><span class="pun">=</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">document</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(“</span><span class="pln">input</span><span class="pun">”);</span><span class="pln"> 
  input</span><span class="pun">.</span><span class="pln">setAttribute</span><span class="pun">(“</span><span class="pln">type</span><span class="pun">”,</span><span class="pln"> </span><span class="pun">“</span><span class="pln">file</span><span class="pun">”);</span><span class="pln"> 
  input</span><span class="pun">.</span><span class="pln">setAttribute</span><span class="pun">(“</span><span class="pln">accept</span><span class="pun">”,</span><span class="pln"> </span><span class="pun">“.</span><span class="pln">mp4</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="pln">ogg</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="pln">ogv</span><span class="pun">,</span><span class="pln"> </span><span class="pun">.</span><span class="pln">webm</span><span class="pun">”);</span><span class="pln"> 
  input</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(“</span><span class="pln">change</span><span class="pun">”,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// عند إختيار ملف </span><span class="pln">
    callback</span><span class="pun">(“</span><span class="pln">file</span><span class="pun">:</span><span class="com">//”+this.value); </span><span class="pln">
  </span><span class="pun">});</span><span class="pln"> 
  input</span><span class="pun">.</span><span class="pln">click</span><span class="pun">()</span><span class="pln"> </span><span class="com">// فتح مُختار الملفات </span><span class="pln">
</span><span class="pun">}</span><span class="pln"> </span></pre>

	<p>
		تجربة استخدام: 
	</p>

	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4" style=""><span class="pln">openFile</span><span class="pun">(</span><span class="pln">alert</span><span class="pun">);</span></pre>

	<h3>
		مشغل الفيديو
	</h3>
</div>

<div id="wmd-preview-section-35">
	<p>
		سنستخدم <a href="http://www.videojs.com/" rel="external nofollow">video.js</a> لتسهيل تصميم المشغّل من خلال سطر الأوامر، اتجه إلى مجلّد المشروع ثم قم بتنصيب <span style="font-family:courier new,courier,monospace;">video.js </span>من مدير الحزم الخاص بـnode.js: 
	</p>

	<pre class="html ipsCode prettyprint prettyprinted" data-pbcklang="html" data-pbcktabsize="4" style=""><span class="pln">npm install videojs </span><span class="pun">–</span><span class="pln">save </span></pre>

	<p>
		كما تحدثنا في بداية الدرس عن استدعاء الحزم في سياق node.js سنحتاج إلى كتابة هذين السطرين: 
	</p>

	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4" style=""><span class="kwd">global</span><span class="pun">.</span><span class="pln">document </span><span class="pun">=</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">document</span><span class="pun">;</span><span class="pln"> 
</span><span class="kwd">global</span><span class="pun">.</span><span class="pln">navigator </span><span class="pun">=</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">navigator</span><span class="pun">;</span><span class="pln"> </span></pre>

	<p>
		من ثم سيمكننا استدعائها بشكل عادي: 
	</p>

	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4" style=""><span class="kwd">var</span><span class="pln"> videojs </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">require</span><span class="pun">(“</span><span class="pln">videojs</span><span class="pun">”);</span><span class="pln"> </span></pre>

	<p>
		من خلال هذا والدّالّة السابقة لفتح الملفات سنكتب دالّة لإنشاء مشغل فيديو من خلال مسار ملف الفيديو من ثم إضافته إلى عنصر المشغّل في المستند الذي كتبناه من قبل: 
	</p>

	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4" style="line-height: 24.8889px;"><span class="kwd">var</span><span class="pln"> playVideo </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> playVideo </span><span class="pun">(</span><span class="pln">src</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
	</span><span class="kwd">var</span><span class="pln"> videojs </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">require</span><span class="pun">(</span><span class="str">"videojs"</span><span class="pun">),</span><span class="pln">
	ext </span><span class="pun">=</span><span class="pln"> </span><span class="str">/[^.]+$/</span><span class="pun">.</span><span class="kwd">exec</span><span class="pun">(</span><span class="pln">src</span><span class="pun">)[</span><span class="lit">0</span><span class="pun">],</span><span class="pln"> </span><span class="com">// صيغة الملفّ</span><span class="pln">
	video </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="str">"video"</span><span class="pun">),</span><span class="pln"> </span><span class="com">// عنصر الفديو</span><span class="pln">
	source </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="str">"source"</span><span class="pun">),</span><span class="pln"> </span><span class="com">// عنصر المصدر للفديو</span><span class="pln">
	player </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">"#player"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// عنصر المشغل في وثيقة html</span><span class="pln">
		
	ext </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">ext </span><span class="pun">==</span><span class="pln"> </span><span class="str">"ogv"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">?</span><span class="pln"> </span><span class="str">"ogg"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> ext</span><span class="pun">;</span><span class="pln"> </span><span class="com">// ملفات ogg قد تملك صيغة ogv </span><span class="pln">
	source</span><span class="pun">.</span><span class="pln">type </span><span class="pun">=</span><span class="pln"> </span><span class="str">"video/"</span><span class="pun">+</span><span class="pln">ext</span><span class="pun">.</span><span class="pln">toLowerCase</span><span class="pun">();</span><span class="pln"> </span><span class="com">// نوع mime للفديو</span><span class="pln">
	source</span><span class="pun">.</span><span class="pln">src </span><span class="pun">=</span><span class="pln"> src</span><span class="pun">;</span><span class="pln"> </span><span class="com">// مسار الفديو</span><span class="pln">
	video</span><span class="pun">.</span><span class="pln">controls </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln"> </span><span class="com">// عناصر التحكّم</span><span class="pln">
	video</span><span class="pun">.</span><span class="pln">autoplay </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln"> </span><span class="com">// تشغيل تلقائي</span><span class="pln">
	video</span><span class="pun">.</span><span class="pln">classList</span><span class="pun">.</span><span class="kwd">add</span><span class="pun">(</span><span class="str">"video-js"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"vjs-default-skin"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// الclass الخاصة بvideojs</span><span class="pln">
	video</span><span class="pun">.</span><span class="pln">appendChild</span><span class="pun">(</span><span class="pln">source</span><span class="pun">);</span><span class="pln"> </span><span class="com">// إضافة عنصر المصدر إلى الفديو</span><span class="pln">
	player</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln"> </span><span class="com">// إزالة جميع العناصر السّابقة</span><span class="pln">
	player</span><span class="pun">.</span><span class="pln">appendChild</span><span class="pun">(</span><span class="pln">video</span><span class="pun">);</span><span class="pln"> </span><span class="com">// إضافة الفديو إلى وثيقة html</span><span class="pln">
	videojs</span><span class="pun">(</span><span class="pln">video</span><span class="pun">)</span><span class="pln"> </span><span class="com">// إستخدام video.js</span><span class="pln">
</span><span class="pun">}</span></pre>

	<p>
		مشكلة nw مع الصيغ مُغلقة المصدر: بشكل افتراضي سيمكنك تشغيل ملفات ogg و webm فقط لكن بسبب مشكلة مع التراخيص، لا تتضمن nw مشغّل لصيغة mp4 و الصوت mp3 اطلع على <a href="https://github.com/nwjs/nw.js/wiki/Using-MP3-&amp;-MP4-%28H.264%29-using-the--video--&amp;--audio--tags." rel="external nofollow">طريقة تضمين الملفّات المُشغلة</a>. 
	</p>

	<p>
		الآن تبقى فتح الملفّ عند الضغط على الزر: 
	</p>

	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4" style=""><span class="pln">window</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(“</span><span class="pln">load</span><span class="pun">”,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
  window</span><span class="pun">.</span><span class="pln">document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(“</span><span class="pln">button</span><span class="com">#play”).addEventListener(“click”, function () { </span><span class="pln">
    openFile</span><span class="pun">(</span><span class="pln">playVideo</span><span class="pun">)</span><span class="pln"> 
  </span><span class="pun">});</span><span class="pln"> 
</span><span class="pun">});</span><span class="pln"> </span></pre>

	<p>
		ليصبح كامل ملف <span style="font-family:courier new,courier,monospace;">app.js</span>: 
	</p>
</div>

<div id="wmd-preview-section-36">
	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4" style=""><span class="str">"use strict"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">global</span><span class="pun">.</span><span class="pln">document </span><span class="pun">=</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">document</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">global</span><span class="pun">.</span><span class="pln">navigator </span><span class="pun">=</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">navigator</span><span class="pun">;</span><span class="pln">
	
</span><span class="kwd">var</span><span class="pln"> nwGui </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">require</span><span class="pun">(</span><span class="str">"nw.gui"</span><span class="pun">),</span><span class="pln">
	</span><span class="typ">Window</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> nwGui</span><span class="pun">.</span><span class="typ">Window</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">();</span><span class="pln">
	
    </span><span class="pun">(</span><span class="kwd">function</span><span class="pun">(</span><span class="pln">window</span><span class="pun">,</span><span class="pln"> nwGui</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Window</span><span class="pun">){</span><span class="pln">
		</span><span class="kwd">var</span><span class="pln"> maximized</span><span class="pun">;</span><span class="pln">
		
		</span><span class="com">// فتح ملف</span><span class="pln">
		</span><span class="kwd">var</span><span class="pln"> openFile </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> openFile </span><span class="pun">(</span><span class="pln">callback</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
			</span><span class="kwd">var</span><span class="pln"> input </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="str">"input"</span><span class="pun">);</span><span class="pln">
			input</span><span class="pun">.</span><span class="pln">setAttribute</span><span class="pun">(</span><span class="str">"type"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"file"</span><span class="pun">);</span><span class="pln">
			input</span><span class="pun">.</span><span class="pln">setAttribute</span><span class="pun">(</span><span class="str">"accept"</span><span class="pun">,</span><span class="pln"> </span><span class="str">".mp4, .ogg, .ogv, .webm"</span><span class="pun">);</span><span class="pln">
			input</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"change"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// عند إختيار ملف</span><span class="pln">
				callback</span><span class="pun">(</span><span class="str">"file://"</span><span class="pun">+</span><span class="kwd">this</span><span class="pun">.</span><span class="kwd">value</span><span class="pun">);</span><span class="pln">
			</span><span class="pun">});</span><span class="pln">
			input</span><span class="pun">.</span><span class="pln">click</span><span class="pun">()</span><span class="pln"> </span><span class="com">// فتح مُختار الملفات</span><span class="pln">
		</span><span class="pun">}</span><span class="pln">
		
		</span><span class="com">// تشغيل فديو</span><span class="pln">
		</span><span class="kwd">var</span><span class="pln"> playVideo </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> playVideo </span><span class="pun">(</span><span class="pln">src</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
			</span><span class="kwd">var</span><span class="pln"> videojs </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">require</span><span class="pun">(</span><span class="str">"videojs"</span><span class="pun">),</span><span class="pln">
			ext </span><span class="pun">=</span><span class="pln"> </span><span class="str">/[^.]+$/</span><span class="pun">.</span><span class="kwd">exec</span><span class="pun">(</span><span class="pln">src</span><span class="pun">)[</span><span class="lit">0</span><span class="pun">],</span><span class="pln"> </span><span class="com">// صيغة الملفّ</span><span class="pln">
			video </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="str">"video"</span><span class="pun">),</span><span class="pln"> </span><span class="com">// عنصر الفديو</span><span class="pln">
			source </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="str">"source"</span><span class="pun">),</span><span class="pln"> </span><span class="com">// عنصر المصدر للفديو</span><span class="pln">
			player </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">"#player"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// عنصر المشغل في وثيقة html</span><span class="pln">
			
			ext </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">ext </span><span class="pun">==</span><span class="pln"> </span><span class="str">"ogv"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">?</span><span class="pln"> </span><span class="str">"ogg"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> ext</span><span class="pun">;</span><span class="pln"> </span><span class="com">// ملفات ogg قد تملك صيغة ogv </span><span class="pln">
			source</span><span class="pun">.</span><span class="pln">type </span><span class="pun">=</span><span class="pln"> </span><span class="str">"video/"</span><span class="pun">+</span><span class="pln">ext</span><span class="pun">.</span><span class="pln">toLowerCase</span><span class="pun">();</span><span class="pln"> </span><span class="com">// نوع mime للفديو</span><span class="pln">
			source</span><span class="pun">.</span><span class="pln">src </span><span class="pun">=</span><span class="pln"> src</span><span class="pun">;</span><span class="pln"> </span><span class="com">// مسار الفديو</span><span class="pln">
			video</span><span class="pun">.</span><span class="pln">controls </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln"> </span><span class="com">// عناصر التحكّم</span><span class="pln">
			video</span><span class="pun">.</span><span class="pln">autoplay </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln"> </span><span class="com">// تشغيل تلقائي</span><span class="pln">
			video</span><span class="pun">.</span><span class="pln">classList</span><span class="pun">.</span><span class="kwd">add</span><span class="pun">(</span><span class="str">"video-js"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"vjs-default-skin"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// الclass الخاصة بvideojs</span><span class="pln">
			video</span><span class="pun">.</span><span class="pln">appendChild</span><span class="pun">(</span><span class="pln">source</span><span class="pun">);</span><span class="pln"> </span><span class="com">// إضافة عنصر المصدر إلى الفديو</span><span class="pln">
			player</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln"> </span><span class="com">// إزالة جميع العناصر السّابقة</span><span class="pln">
			player</span><span class="pun">.</span><span class="pln">appendChild</span><span class="pun">(</span><span class="pln">video</span><span class="pun">);</span><span class="pln"> </span><span class="com">// إضافة الفديو إلى وثيقة html</span><span class="pln">
			videojs</span><span class="pun">(</span><span class="pln">video</span><span class="pun">)</span><span class="pln"> </span><span class="com">// إستخدام video.js</span><span class="pln">
		</span><span class="pun">}</span><span class="pln">
		
		window</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"load"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
			</span><span class="com">// زر فتح فديو</span><span class="pln">
			window</span><span class="pun">.</span><span class="pln">document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">"button#play"</span><span class="pun">).</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
				openFile</span><span class="pun">(</span><span class="pln">playVideo</span><span class="pun">)</span><span class="pln">
			</span><span class="pun">});</span><span class="pln">
		</span><span class="pun">});</span><span class="pln">	
	</span><span class="pun">})</span><span class="pln">
</span><span class="pun">(</span><span class="pln">window</span><span class="pun">,</span><span class="pln"> nwGui</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Window</span><span class="pun">);</span></pre>

	<h3 id="تصميم-التطبيق">
		تصميم التطبيق
	</h3>

	<p>
		بداخل مُستند html أضف مسار ملفّ css الافتراضي لـ<span style="font-family:courier new,courier,monospace;">video.js</span> الموجود داخل مجلد <span style="font-family:courier new,courier,monospace;">node_modules</span>: <br>
		<br>
		ثم سنلغي شريط الأدوات الخاص بـnw بداخل ملف الحزمة (<span style="font-family:courier new,courier,monospace;">package.json</span>) وبداخل العنصر window أضف ما يلي:
	</p>

	<pre class="html ipsCode prettyprint prettyprinted" data-pbcklang="html" data-pbcktabsize="4" style=""><span class="pun">“</span><span class="pln">toolbar</span><span class="pun">”:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span></pre>

	<p>
		من ثم سننشئ ملف تصميم <span style="font-family:courier new,courier,monospace;">src/style.css</span>: 
	</p>

	<pre class="css ipsCode prettyprint prettyprinted" data-pbcklang="css" data-pbcktabsize="4" style=""><span class="pln">html</span><span class="pun">,</span><span class="pln"> 
body</span><span class="pun">{</span><span class="pln"> 
  width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%;</span><span class="pln"> 
  height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%;</span><span class="pln"> 
  background</span><span class="pun">:</span><span class="pln"> </span><span class="com">#ccc; </span><span class="pln">
  direction</span><span class="pun">:</span><span class="pln"> rtl</span><span class="pun">;</span><span class="pln"> 
  margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> 
</span><span class="pun">}</span><span class="pln"> 

</span><span class="com">/* زر التشغيل */</span><span class="pln"> 
</span><span class="com">#play{ </span><span class="pln">
  height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">25px</span><span class="pun">;</span><span class="pln"> 
  background</span><span class="pun">:</span><span class="pln"> white</span><span class="pun">;</span><span class="pln"> 
  padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2px</span><span class="pln"> </span><span class="lit">20px</span><span class="pun">;</span><span class="pln"> 
  box</span><span class="pun">-</span><span class="pln">sizing</span><span class="pun">:</span><span class="pln"> border</span><span class="pun">-</span><span class="pln">box</span><span class="pun">;</span><span class="pln"> 
  border</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1px</span><span class="pln"> </span><span class="com">#ccc solid </span><span class="pln">
</span><span class="pun">}</span><span class="pln"> 

</span><span class="com">#play:hover{ </span><span class="pln">
  box</span><span class="pun">-</span><span class="pln">shadow</span><span class="pun">:</span><span class="pln"> inset </span><span class="lit">0</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">1px</span><span class="pln"> </span><span class="com">#333 </span><span class="pln">
</span><span class="pun">}</span><span class="pln"> 

</span><span class="com">/* المُشغل */</span><span class="pln"> 
</span><span class="com">#player{ </span><span class="pln">
  background</span><span class="pun">:</span><span class="pln"> black</span><span class="pun">;</span><span class="pln"> 
  width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%;</span><span class="pln"> 
  height</span><span class="pun">:</span><span class="pln"> calc</span><span class="pun">(</span><span class="lit">100</span><span class="pun">%</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">25px</span><span class="pun">)</span><span class="pln"> 
</span><span class="pun">}</span><span class="pln"> 

</span><span class="com">#player &gt; .video-js{ </span><span class="pln">
  width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%</span><span class="pln"> </span><span class="pun">!</span><span class="pln">important</span><span class="pun">;</span><span class="pln"> 
  height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%</span><span class="pln"> </span><span class="pun">!</span><span class="pln">important 
</span><span class="pun">}</span><span class="pln"> </span></pre>

	<p>
		إضافته من خلال مُستند html: <br>
		<br>
		كان من الأفضل استخدام <a href="https://github.com/nwjs/nw.js/wiki/Window-menu" rel="external nofollow">قائمة النظام</a> لعرض زر تشغيل الفيديو لكن nw لا تدعم الاتجاه من اليمين إلى اليسار بشكل كامل إلى الآن، لذا سنضيف السطر التالي إلى ملف الحزمة كي تظهر من اليمين إلى اليسار: 
	</p>

	<pre class="html ipsCode prettyprint prettyprinted" data-pbcklang="html" data-pbcktabsize="4" style=""><span class="pun">“</span><span class="pln">chromium</span><span class="pun">-</span><span class="pln">args</span><span class="pun">”:</span><span class="pln"> </span><span class="pun">“–</span><span class="pln">lang</span><span class="pun">=</span><span class="pln">ar</span><span class="pun">”</span><span class="pln"> </span></pre>

	<p>
		بدلًا من ذلك سنقوم بإنشاء إطار مُخصص للنافذة لتبدو بشكلٍ أفضل في مختلف الأنظمة.
	</p>
</div>

<div id="wmd-preview-section-37">
	<h3 id="تخصيص-إطار-النافذة">
		تخصيص إطار النافذة
	</h3>

	<p>
		بداخل ملف الحزمة (<span style="font-family:courier new,courier,monospace;">package.json</span>) وبداخل عنصر <span style="font-family:courier new,courier,monospace;">window</span> سنلغي الإطار الافتراضي:
	</p>

	<pre class="html ipsCode prettyprint prettyprinted" data-pbcklang="html" data-pbcktabsize="4" style=""><span class="pun">“</span><span class="pln">frame</span><span class="pun">”:</span><span class="pln"> </span><span class="kwd">false</span><span class="pln"> </span></pre>

	<p>
		من ثم بداخل مستند html سنضيف أزرار النافذة في أول عنصر جسم الصفحة (body).<br>
		<br>
		سنضيف و نحذف بعض الخصائص من ملف <span style="font-family:courier new,courier,monospace;">src/style.css</span> ليصبح شكل النافذة شبيه بنافذة نظام OS X: 
	</p>

	<pre class="css ipsCode prettyprint prettyprinted" data-pbcklang="css" data-pbcktabsize="4" style=""><span class="pln">html</span><span class="pun">,</span><span class="pln"> 
body</span><span class="pun">{</span><span class="pln"> 
  width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%;</span><span class="pln"> 
  height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%;</span><span class="pln"> 
  background</span><span class="pun">:</span><span class="pln"> </span><span class="com">#ccc; </span><span class="pln">
  direction</span><span class="pun">:</span><span class="pln"> rtl</span><span class="pun">;</span><span class="pln"> 
  margin</span><span class="pun">:</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> 
</span><span class="pun">}</span><span class="pln"> 

</span><span class="com">/* زر التشغيل */</span><span class="pln"> 
</span><span class="com">#play{ </span><span class="pln">
  </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">app</span><span class="pun">-</span><span class="pln">region</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">no</span><span class="pun">-</span><span class="pln">drag</span><span class="pun">;</span><span class="pln"> 
  height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">25px</span><span class="pun">;</span><span class="pln"> 
  background</span><span class="pun">:</span><span class="pln"> white</span><span class="pun">;</span><span class="pln"> 
  padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2px</span><span class="pln"> </span><span class="lit">20px</span><span class="pun">;</span><span class="pln"> 
  box</span><span class="pun">-</span><span class="pln">sizing</span><span class="pun">:</span><span class="pln"> border</span><span class="pun">-</span><span class="pln">box</span><span class="pun">;</span><span class="pln"> 
  border</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1px</span><span class="pln"> </span><span class="com">#ccc solid; </span><span class="pln">
  position</span><span class="pun">:</span><span class="pln"> absolute</span><span class="pun">;</span><span class="pln"> 
  right</span><span class="pun">:</span><span class="pln"> </span><span class="lit">5px</span><span class="pun">;</span><span class="pln"> 
  top</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2px</span><span class="pln"> 
</span><span class="pun">}</span><span class="pln"> 

</span><span class="com">#play:hover{ </span><span class="pln">
  box</span><span class="pun">-</span><span class="pln">shadow</span><span class="pun">:</span><span class="pln"> inset </span><span class="lit">0</span><span class="pln"> </span><span class="lit">0</span><span class="pln"> </span><span class="lit">1px</span><span class="pln"> </span><span class="com">#333 </span><span class="pln">
</span><span class="pun">}</span><span class="pln"> 

</span><span class="com">/* المُشغل */</span><span class="pln"> 
</span><span class="com">#player{ </span><span class="pln">
  background</span><span class="pun">:</span><span class="pln"> black</span><span class="pun">;</span><span class="pln"> 
  width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%;</span><span class="pln"> 
  height</span><span class="pun">:</span><span class="pln"> calc</span><span class="pun">(</span><span class="lit">100</span><span class="pun">%</span><span class="pln"> </span><span class="pun">-</span><span class="pln"> </span><span class="lit">25px</span><span class="pun">)</span><span class="pln"> 
</span><span class="pun">}</span><span class="pln"> 

</span><span class="com">#player &gt; .video-js{ </span><span class="pln">
  width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%</span><span class="pln"> </span><span class="pun">!</span><span class="pln">important</span><span class="pun">;</span><span class="pln"> 
  height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%</span><span class="pln"> </span><span class="pun">!</span><span class="pln">important 
</span><span class="pun">}</span><span class="pln"> 

</span><span class="com">/* النافذة */</span><span class="pln"> 
body</span><span class="pun">{</span><span class="pln"> 
  box</span><span class="pun">-</span><span class="pln">sizing</span><span class="pun">:</span><span class="pln"> border</span><span class="pun">-</span><span class="pln">box</span><span class="pun">;</span><span class="pln"> 
  border</span><span class="pun">:</span><span class="pln"> </span><span class="com">#DDDDDC 5px solid </span><span class="pln">
</span><span class="pun">}</span><span class="pln"> 

</span><span class="pun">.</span><span class="pln">window</span><span class="pun">-</span><span class="pln">toolbar</span><span class="pun">{</span><span class="pln"> 
  </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">app</span><span class="pun">-</span><span class="pln">region</span><span class="pun">:</span><span class="pln"> drag</span><span class="pun">;</span><span class="pln"> 
  background</span><span class="pun">:</span><span class="pln"> </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">linear</span><span class="pun">-</span><span class="pln">gradient</span><span class="pun">(#</span><span class="pln">DDDDDC</span><span class="pun">,</span><span class="pln"> </span><span class="com">#C2C2C2); </span><span class="pln">
  height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">25px</span><span class="pun">;</span><span class="pln"> 
  direction</span><span class="pun">:</span><span class="pln"> ltr</span><span class="pun">;</span><span class="pln"> 
  padding</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2px</span><span class="pln"> </span><span class="lit">5px</span><span class="pun">;</span><span class="pln"> 
  box</span><span class="pun">-</span><span class="pln">sizing</span><span class="pun">:</span><span class="pln"> border</span><span class="pun">-</span><span class="pln">box 
</span><span class="pun">}</span><span class="pln"> 

</span><span class="pun">.</span><span class="pln">window</span><span class="pun">-</span><span class="pln">toolbar </span><span class="pun">&gt;</span><span class="pln"> label</span><span class="pun">.</span><span class="pln">title</span><span class="pun">{</span><span class="pln"> 
  position</span><span class="pun">:</span><span class="pln"> absolute</span><span class="pun">;</span><span class="pln"> 
  left</span><span class="pun">:</span><span class="pln"> </span><span class="lit">50</span><span class="pun">%;</span><span class="pln"> 
  transform</span><span class="pun">:</span><span class="pln"> translate</span><span class="pun">(-</span><span class="lit">50</span><span class="pun">%,</span><span class="pln"> </span><span class="lit">0</span><span class="pun">)</span><span class="pln"> 
</span><span class="pun">}</span><span class="pln"> 

</span><span class="pun">.</span><span class="pln">window</span><span class="pun">-</span><span class="pln">toolbar</span><span class="pun">-</span><span class="pln">button</span><span class="pun">{</span><span class="pln"> 
  </span><span class="pun">-</span><span class="pln">webkit</span><span class="pun">-</span><span class="pln">app</span><span class="pun">-</span><span class="pln">region</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">no</span><span class="pun">-</span><span class="pln">drag</span><span class="pun">;</span><span class="pln"> 
  width</span><span class="pun">:</span><span class="pln"> </span><span class="lit">12px</span><span class="pun">;</span><span class="pln"> 
  height</span><span class="pun">:</span><span class="pln"> </span><span class="lit">12px</span><span class="pun">;</span><span class="pln"> 
  border</span><span class="pun">-</span><span class="pln">radius</span><span class="pun">:</span><span class="pln"> </span><span class="lit">100</span><span class="pun">%;</span><span class="pln"> 
  display</span><span class="pun">:</span><span class="pln"> </span><span class="kwd">inline</span><span class="pun">-</span><span class="pln">block</span><span class="pun">;</span><span class="pln"> 
  cursor</span><span class="pun">:</span><span class="pln"> pointer</span><span class="pun">;</span><span class="pln"> 
  margin</span><span class="pun">-</span><span class="pln">right</span><span class="pun">:</span><span class="pln"> </span><span class="lit">2px</span><span class="pln"> 
</span><span class="pun">}</span><span class="pln"> 

</span><span class="pun">.</span><span class="pln">window</span><span class="pun">-</span><span class="pln">toolbar</span><span class="pun">-</span><span class="pln">button</span><span class="pun">.</span><span class="pln">close</span><span class="pun">{</span><span class="pln"> background</span><span class="pun">:</span><span class="pln"> </span><span class="com">#FD4E4E } </span><span class="pln">
</span><span class="pun">.</span><span class="pln">window</span><span class="pun">-</span><span class="pln">toolbar</span><span class="pun">-</span><span class="pln">button</span><span class="pun">.</span><span class="pln">maximize</span><span class="pun">{</span><span class="pln"> background</span><span class="pun">:</span><span class="pln"> </span><span class="com">#96D16F } </span><span class="pln">
</span><span class="pun">.</span><span class="pln">window</span><span class="pun">-</span><span class="pln">toolbar</span><span class="pun">-</span><span class="pln">button</span><span class="pun">.</span><span class="pln">minimize</span><span class="pun">{</span><span class="pln"> background</span><span class="pun">:</span><span class="pln"> </span><span class="com">#F3BB55 } </span></pre>

	<p>
		<strong>مُلاحظة:</strong> الخاصية <span style="font-family:courier new,courier,monospace;">webkit-app-region-</span> المسؤولة عن جعل العنصر قابل للسحب والإفلات أيضًا يُمكن التحكّم بموقع النافذة من هذا العنصر لهذا استخدمناه في شريط أدوات النافذة لكن هذا العنصر لن يكون قابل للضغط أو المرور عليه لذلك يجب تعطيلها لعناصر التحكّم بداخله. 
	</p>

	<p>
		لنكتب بعض الشيفرات بداخل ملفّ <span style="font-family:courier new,courier,monospace;">src/app.js</span> لإضافة الحياة لشريط الأدوات. توفّر nw بعض التوابع للتحكم بالنافذة ما سنحتاجه للعمل: 
	</p>

	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4" style=""><span class="kwd">require</span><span class="pun">(“</span><span class="pln">nw</span><span class="pun">.</span><span class="pln">gui</span><span class="pun">”).</span><span class="typ">Window</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">().</span><span class="pln">close</span><span class="pun">();</span><span class="pln"> </span><span class="com">// إغلاق النافذة الحالية فقط </span><span class="pln">
</span><span class="kwd">require</span><span class="pun">(“</span><span class="pln">nw</span><span class="pun">.</span><span class="pln">gui</span><span class="pun">”).</span><span class="typ">App</span><span class="pun">.</span><span class="pln">quit</span><span class="pun">();</span><span class="pln"> </span><span class="com">// إغلاق التطبيق بجميع النوافذ </span><span class="pln">
</span><span class="kwd">require</span><span class="pun">(“</span><span class="pln">nw</span><span class="pun">.</span><span class="pln">gui</span><span class="pun">”).</span><span class="typ">Window</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">().</span><span class="pln">minimize</span><span class="pun">();</span><span class="pln"> </span><span class="com">// تصغير النافذة إلى شريط التطبيقات </span><span class="pln">
</span><span class="kwd">require</span><span class="pun">(“</span><span class="pln">nw</span><span class="pun">.</span><span class="pln">gui</span><span class="pun">”).</span><span class="typ">Window</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">().</span><span class="pln">maximize</span><span class="pun">();</span><span class="pln"> </span><span class="com">// ملء الشاشة بالنافذة </span><span class="pln">
</span><span class="kwd">require</span><span class="pun">(“</span><span class="pln">nw</span><span class="pun">.</span><span class="pln">gui</span><span class="pun">”).</span><span class="typ">Window</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">().</span><span class="pln">unmaximize</span><span class="pun">();</span><span class="pln"> </span><span class="com">// إرجاع النافذة </span></pre>

	<p>
		أولًا زر الإغلاق: 
	</p>

	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4" style=""><span class="kwd">var</span><span class="pln"> nwGui </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">require</span><span class="pun">(“</span><span class="pln">nw</span><span class="pun">.</span><span class="pln">gui</span><span class="pun">”);</span><span class="pln"> 

</span><span class="com">// زر إغلاق التطبيق </span><span class="pln">
window</span><span class="pun">.</span><span class="pln">document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(“.</span><span class="pln">close</span><span class="pun">”).</span><span class="pln">addEventListener</span><span class="pun">(“</span><span class="pln">click</span><span class="pun">”,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
  nwGui</span><span class="pun">.</span><span class="typ">App</span><span class="pun">.</span><span class="pln">quit</span><span class="pun">();</span><span class="pln"> 
</span><span class="pun">});</span><span class="pln"> </span></pre>

	<p>
		ثانيًا زر إخفاء النافذة إلى شريط التطبيقات:
	</p>

	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4" style=""><span class="kwd">var</span><span class="pln"> nwGui </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">require</span><span class="pun">(</span><span class="str">"nw.gui"</span><span class="pun">),</span><span class="pln"> </span><span class="typ">Window</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> nwGui</span><span class="pun">.</span><span class="typ">Window</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">();</span><span class="pln"> </span><span class="com">// زر تصغير النافذة إلى شريط التطبيقات window.document.querySelector(".minimize").addEventListener("click", function() { </span><span class="pln">
  </span><span class="typ">Window</span><span class="pun">.</span><span class="pln">minimize</span><span class="pun">()</span><span class="pln"> 
</span><span class="pun">});</span></pre>

	<p>
		زر ملء النافذة لكن أولًا سنضيف مراقب للحدثين <span style="font-family:courier new,courier,monospace;">maximize</span> و <span style="font-family:courier new,courier,monospace;">unmaximize</span> لمعرفة هل النافذة بكامل الحجم أو لا، حيث لا توفّر nw أيّة <abbr title="واجهة برمجية | Application Programming Interface"><abbr title="Application Programming Interface | واجهة برمجية">API</abbr></abbr> لمعرفة ذلك: 
	</p>

	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4" style=""><span class="kwd">var</span><span class="pln"> nwGui </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">require</span><span class="pun">(“</span><span class="pln">nw</span><span class="pun">.</span><span class="pln">gui</span><span class="pun">”),</span><span class="pln"> 
</span><span class="typ">Window</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> nwGui</span><span class="pun">.</span><span class="typ">Window</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">(),</span><span class="pln"> 
maximized </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">

</span><span class="com">// مراقب للحدث maximize </span><span class="pln">
</span><span class="typ">Window</span><span class="pun">.</span><span class="pln">on</span><span class="pun">(</span><span class="str">"maximize"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(){</span><span class="pln"> maximized </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln"> </span><span class="pun">});</span><span class="pln"> 

</span><span class="com">// مراقب للحدث unmaximize </span><span class="pln">
</span><span class="typ">Window</span><span class="pun">.</span><span class="pln">on</span><span class="pun">(</span><span class="str">"unmaximize"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(){</span><span class="pln"> maximized </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln"> </span><span class="pun">});</span></pre>

	<p>
		من خلال هذا وعند الضغط على زر الملئ إما أن تذهب النافذة لكامل الحجم أو تعود لحجمها الطبيعي: 
	</p>

	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4" style=""><span class="pln">window</span><span class="pun">.</span><span class="pln">document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(“.</span><span class="pln">maximize</span><span class="pun">”).</span><span class="pln">addEventListener</span><span class="pun">(“</span><span class="pln">click</span><span class="pun">”,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
  maximized </span><span class="pun">?</span><span class="pln"> </span><span class="typ">Window</span><span class="pun">.</span><span class="pln">unmaximize</span><span class="pun">()</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="typ">Window</span><span class="pun">.</span><span class="pln">maximize</span><span class="pun">()</span><span class="pln"> 
</span><span class="pun">});</span><span class="pln"> </span></pre>

	<p>
		يجب أن يكون كامل ملف <span style="font-family:courier new,courier,monospace;">src/app.js</span> بهذا الشكل:
	</p>

	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4" style="line-height: 24.8889px;"><span class="str">"use strict"</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">global</span><span class="pun">.</span><span class="pln">document </span><span class="pun">=</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">document</span><span class="pun">;</span><span class="pln">
</span><span class="kwd">global</span><span class="pun">.</span><span class="pln">navigator </span><span class="pun">=</span><span class="pln"> window</span><span class="pun">.</span><span class="pln">navigator</span><span class="pun">;</span><span class="pln">
	
</span><span class="kwd">var</span><span class="pln"> nwGui </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">require</span><span class="pun">(</span><span class="str">"nw.gui"</span><span class="pun">),</span><span class="pln">
	</span><span class="typ">Window</span><span class="pln"> </span><span class="pun">=</span><span class="pln"> nwGui</span><span class="pun">.</span><span class="typ">Window</span><span class="pun">.</span><span class="kwd">get</span><span class="pun">();</span><span class="pln">
	
    </span><span class="pun">(</span><span class="kwd">function</span><span class="pun">(</span><span class="pln">window</span><span class="pun">,</span><span class="pln"> nwGui</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Window</span><span class="pun">){</span><span class="pln">
		</span><span class="kwd">var</span><span class="pln"> maximized</span><span class="pun">;</span><span class="pln">
		
		</span><span class="com">// فتح ملف</span><span class="pln">
		</span><span class="kwd">var</span><span class="pln"> openFile </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> openFile </span><span class="pun">(</span><span class="pln">callback</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
			</span><span class="kwd">var</span><span class="pln"> input </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="str">"input"</span><span class="pun">);</span><span class="pln">
			input</span><span class="pun">.</span><span class="pln">setAttribute</span><span class="pun">(</span><span class="str">"type"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"file"</span><span class="pun">);</span><span class="pln">
			input</span><span class="pun">.</span><span class="pln">setAttribute</span><span class="pun">(</span><span class="str">"accept"</span><span class="pun">,</span><span class="pln"> </span><span class="str">".mp4, .ogg, .ogv, .webm"</span><span class="pun">);</span><span class="pln">
			input</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"change"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> </span><span class="com">// عند إختيار ملف</span><span class="pln">
				callback</span><span class="pun">(</span><span class="str">"file://"</span><span class="pun">+</span><span class="kwd">this</span><span class="pun">.</span><span class="kwd">value</span><span class="pun">);</span><span class="pln">
			</span><span class="pun">});</span><span class="pln">
			input</span><span class="pun">.</span><span class="pln">click</span><span class="pun">()</span><span class="pln"> </span><span class="com">// فتح مُختار الملفات</span><span class="pln">
		</span><span class="pun">}</span><span class="pln">
		
		</span><span class="com">// تشغيل فديو</span><span class="pln">
		</span><span class="kwd">var</span><span class="pln"> playVideo </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> playVideo </span><span class="pun">(</span><span class="pln">src</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
			</span><span class="kwd">var</span><span class="pln"> videojs </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">require</span><span class="pun">(</span><span class="str">"videojs"</span><span class="pun">),</span><span class="pln">
			ext </span><span class="pun">=</span><span class="pln"> </span><span class="str">/[^.]+$/</span><span class="pun">.</span><span class="kwd">exec</span><span class="pun">(</span><span class="pln">src</span><span class="pun">)[</span><span class="lit">0</span><span class="pun">],</span><span class="pln"> </span><span class="com">// صيغة الملفّ</span><span class="pln">
			video </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="str">"video"</span><span class="pun">),</span><span class="pln"> </span><span class="com">// عنصر الفديو</span><span class="pln">
			source </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">createElement</span><span class="pun">(</span><span class="str">"source"</span><span class="pun">),</span><span class="pln"> </span><span class="com">// عنصر المصدر للفديو</span><span class="pln">
			player </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">"#player"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// عنصر المشغل في وثيقة html</span><span class="pln">
			
			ext </span><span class="pun">=</span><span class="pln"> </span><span class="pun">(</span><span class="pln">ext </span><span class="pun">==</span><span class="pln"> </span><span class="str">"ogv"</span><span class="pun">)</span><span class="pln"> </span><span class="pun">?</span><span class="pln"> </span><span class="str">"ogg"</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> ext</span><span class="pun">;</span><span class="pln"> </span><span class="com">// ملفات ogg قد تملك صيغة ogv </span><span class="pln">
			source</span><span class="pun">.</span><span class="pln">type </span><span class="pun">=</span><span class="pln"> </span><span class="str">"video/"</span><span class="pun">+</span><span class="pln">ext</span><span class="pun">.</span><span class="pln">toLowerCase</span><span class="pun">();</span><span class="pln"> </span><span class="com">// نوع mime للفديو</span><span class="pln">
			source</span><span class="pun">.</span><span class="pln">src </span><span class="pun">=</span><span class="pln"> src</span><span class="pun">;</span><span class="pln"> </span><span class="com">// مسار الفديو</span><span class="pln">
			video</span><span class="pun">.</span><span class="pln">controls </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln"> </span><span class="com">// عناصر التحكّم</span><span class="pln">
			video</span><span class="pun">.</span><span class="pln">autoplay </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln"> </span><span class="com">// تشغيل تلقائي</span><span class="pln">
			video</span><span class="pun">.</span><span class="pln">classList</span><span class="pun">.</span><span class="kwd">add</span><span class="pun">(</span><span class="str">"video-js"</span><span class="pun">,</span><span class="pln"> </span><span class="str">"vjs-default-skin"</span><span class="pun">);</span><span class="pln"> </span><span class="com">// الclass الخاصة بvideojs</span><span class="pln">
			video</span><span class="pun">.</span><span class="pln">appendChild</span><span class="pun">(</span><span class="pln">source</span><span class="pun">);</span><span class="pln"> </span><span class="com">// إضافة عنصر المصدر إلى الفديو</span><span class="pln">
			player</span><span class="pun">.</span><span class="pln">innerHTML </span><span class="pun">=</span><span class="pln"> </span><span class="str">""</span><span class="pun">;</span><span class="pln"> </span><span class="com">// إزالة جميع العناصر السّابقة</span><span class="pln">
			player</span><span class="pun">.</span><span class="pln">appendChild</span><span class="pun">(</span><span class="pln">video</span><span class="pun">);</span><span class="pln"> </span><span class="com">// إضافة الفديو إلى وثيقة html</span><span class="pln">
			videojs</span><span class="pun">(</span><span class="pln">video</span><span class="pun">)</span><span class="pln"> </span><span class="com">// إستخدام video.js</span><span class="pln">
		</span><span class="pun">}</span><span class="pln">
		
		window</span><span class="pun">.</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"load"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
			</span><span class="com">// زر فتح فديو</span><span class="pln">
			window</span><span class="pun">.</span><span class="pln">document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">"button#play"</span><span class="pun">).</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
				openFile</span><span class="pun">(</span><span class="pln">playVideo</span><span class="pun">)</span><span class="pln">
			</span><span class="pun">});</span><span class="pln">
			
			</span><span class="com">// زر إغلاق التطبيق</span><span class="pln">
			window</span><span class="pun">.</span><span class="pln">document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">".close"</span><span class="pun">).</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
				nwGui</span><span class="pun">.</span><span class="typ">App</span><span class="pun">.</span><span class="pln">quit</span><span class="pun">()</span><span class="pln">
			</span><span class="pun">});</span><span class="pln">
	
			</span><span class="com">// مراقب للحدث maximize</span><span class="pln">
			</span><span class="typ">Window</span><span class="pun">.</span><span class="pln">on</span><span class="pun">(</span><span class="str">"maximize"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(){</span><span class="pln">
				maximized </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">true</span><span class="pun">;</span><span class="pln">
			</span><span class="pun">});</span><span class="pln">
			</span><span class="com">// مراقب للحدث unmaximize</span><span class="pln">
			</span><span class="typ">Window</span><span class="pun">.</span><span class="pln">on</span><span class="pun">(</span><span class="str">"unmaximize"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">(){</span><span class="pln">
				maximized </span><span class="pun">=</span><span class="pln"> </span><span class="kwd">false</span><span class="pun">;</span><span class="pln">
			</span><span class="pun">});</span><span class="pln">
			
			</span><span class="com">// زر تصغير النافذة إلى شريط التطبيقات</span><span class="pln">
			window</span><span class="pun">.</span><span class="pln">document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">".minimize"</span><span class="pun">).</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
				</span><span class="typ">Window</span><span class="pun">.</span><span class="pln">minimize</span><span class="pun">()</span><span class="pln">
			</span><span class="pun">});</span><span class="pln">
			
			</span><span class="com">// زر الملء</span><span class="pln">
			window</span><span class="pun">.</span><span class="pln">document</span><span class="pun">.</span><span class="pln">querySelector</span><span class="pun">(</span><span class="str">".maximize"</span><span class="pun">).</span><span class="pln">addEventListener</span><span class="pun">(</span><span class="str">"click"</span><span class="pun">,</span><span class="pln"> </span><span class="kwd">function</span><span class="pln"> </span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln">
				maximized </span><span class="pun">?</span><span class="pln"> </span><span class="typ">Window</span><span class="pun">.</span><span class="pln">unmaximize</span><span class="pun">()</span><span class="pln"> </span><span class="pun">:</span><span class="pln"> </span><span class="typ">Window</span><span class="pun">.</span><span class="pln">maximize</span><span class="pun">()</span><span class="pln">
			</span><span class="pun">});</span><span class="pln">
		</span><span class="pun">});</span><span class="pln">	
	</span><span class="pun">})</span><span class="pln">
</span><span class="pun">(</span><span class="pln">window</span><span class="pun">,</span><span class="pln"> nwGui</span><span class="pun">,</span><span class="pln"> </span><span class="typ">Window</span><span class="pun">);</span></pre>

	<p>
		صورة للشكل النهائي: 
	</p>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_11/app.png.421bcaac19468286d0fe31a67e0cabb2.png" data-fileid="8151" data-fileext="png" rel=""><img alt="app.thumb.png.790447be85d97b1044ee5fcc44" class="ipsImage ipsImage_thumbnailed" data-fileid="8151" src="https://academy.hsoub.com/uploads/monthly_2015_11/app.thumb.png.790447be85d97b1044ee5fcc444109a0.png"></a> 
	</p>

	<p>
		إن لم يظهر التطبيق بنفس الشكل فإليك <a class="ipsAttachLink" href="https://academy.hsoub.com/applications/core/interface/file/attachment.php?id=8157" data-fileid="8157" data-fileext="rar" rel="">ملفات التطبيق النهائية</a>.
	</p>
</div>

<div id="wmd-preview-section-38">
	<h2 id="بناء-الملف-التنفيذي">
		بناء الملف التنفيذي
	</h2>

	<p>
		لو أردنا إتباع الأسلوب التقليدي فنحن نحتاج إلى أنظمة التشغيل الثلاثة لبناء التطبيق في كل واحد منها على حدى، بدلًا من ذلك سنستخدم <a href="https://github.com/nwjs/nw-builder" rel="external nofollow">nwbuild</a> لبناء التطبيق من خلال نظام تشغيل واحد إلى جميع أنظمة التشغيل. 
	</p>

	<p>
		من مدير حزم npm قم بتركيب <span style="font-family:courier new,courier,monospace;">nwbuild</span> : 
	</p>

	<pre class="html ipsCode prettyprint prettyprinted" data-pbcklang="html" data-pbcktabsize="4" style=""><span class="pln">npm install nwbuild </span><span class="pun">-</span><span class="pln">g </span></pre>

	<p>
		أنظمة التشغيل المتوفرة لـnwbuild:
	</p>

	<ul>
		<li>
			win32 # Windows 32bit 
		</li>
		<li>
			win64 # Windows 64bit 
		</li>
		<li>
			win # Windows 64bit مع 32bit 
		</li>
		<li>
			osx32 # Mac OS 32bit 
		</li>
		<li>
			osx64 # Mac OS 64bit 
		</li>
		<li>
			osx # Mac OS 64bit مع 32bit 
		</li>
		<li>
			linux32 # Linux 32bit 
		</li>
		<li>
			linux64 #  Linux 64bit 
		</li>
		<li>
			linux # Linux 64bit مع 32bit 
		</li>
	</ul>

	<p>
		ليعمل على أنظمة التشغيل الثلاث سنبنيه لـlinux ، osx64 و win32، اتّجه إلى مجلد التطبيق ونفّذ:
	</p>

	<pre class="html ipsCode prettyprint prettyprinted" data-pbcklang="html" data-pbcktabsize="4" style=""><span class="pln">nwbuild </span><span class="pun">-</span><span class="pln">p linux</span><span class="pun">,</span><span class="pln">osx64</span><span class="pun">,</span><span class="pln">win32 </span><span class="pun">./</span></pre>

	<p>
		سيعمل أولًا على تحميل ملفات البناء لأنظمة التشغيل من ثم بناء الملفات التنفيذية، ستلاحظ أن متوسط الحجم 50 ميغابايت للملفّ الواحد بسبب تضمين المتصفحات والملفات التشغيلية.
	</p>
</div>

<div id="wmd-preview-section-39">
	<h2 id="التالي">
		التالي
	</h2>

	<p>
		سيكون من الرائع <a href="https://academy.hsoub.com/programming/javascript/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-reactjs-%D9%85%D9%83%D8%AA%D8%A8%D8%A9-%D8%AA%D8%B7%D9%88%D9%8A%D8%B1-%D8%A7%D9%84%D9%88%D8%A7%D8%AC%D9%87%D8%A7%D8%AA-%D8%A7%D9%84%D8%B1%D8%B3%D9%88%D9%85%D9%8A%D8%A9-%D9%85%D9%86-%D9%81%D9%8A%D8%B3-%D8%A8%D9%88%D9%83-r112/" rel="">تعلم react</a> لبناء تطبيقات سطح مكتب رائعة باستخدام nw مع react.
	</p>
</div>

<div id="wmd-preview-section-40">
	<h2 id="مصادر">
		مصادر
	</h2>

	<ol>
		<li>
			<a href="https://github.com/nwjs/nw.js/wiki/window" rel="external nofollow">nw window</a>
		</li>
		<li>
			<a href="https://github.com/nwjs/nw.js/wiki/App" rel="external nofollow">nw App</a>
		</li>
		<li>
			<a href="https://github.com/nwjs/nw.js/wiki/Differences-of-JavaScript-contexts" rel="external nofollow">nw javascript contexts</a>
		</li>
		<li>
			<a href="https://github.com/nwjs/nw-builder" rel="external nofollow">nw build</a>
		</li>
	</ol>

	<h2>
		هوامش
	</h2>

	<p>
		1 - كروميوم (Chromium) هو متصفح ويب مفتوح المصدر، يأخذ متصفح Google كروم الكود المصدري منه. المتصفحان يشتركان في أغلبية الشِفرة البرمجية والميزات، وإن كانت هناك بعض الاختلافات الطفيفة في ملامح كلا منهما وفي تراخيص الأستخدام أيضا. المصدر: ويكيبيديا.
	</p>
</div>
]]></description><guid isPermaLink="false">208</guid><pubDate>Sun, 29 Nov 2015 22:35:00 +0000</pubDate></item><item><title>&#x623;&#x633;&#x627;&#x633;&#x64A;&#x627;&#x62A; &#x627;&#x644;&#x62A;&#x639;&#x627;&#x645;&#x644; &#x645;&#x639; &#x639;&#x646;&#x635;&#x631; Canvas &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A3%D8%B3%D8%A7%D8%B3%D9%8A%D8%A7%D8%AA-%D8%A7%D9%84%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%B9%D9%86%D8%B5%D8%B1-canvas-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-r207/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_11/canvas-javascript.png.ec0c06e37eab7bdc19e6f0b9d387ad72.png" /></p>

<div id="wmd-preview-section-19">
	<p id="التعامل-مع-عنصر-canvas-باستخدام-جافا-سكربت-أساسيات">
		إن عالم الويب أصبح جزءًا لا يتجزأ من حياتنا اليومية هذا ما يجعلنا نبتكر طُرقًا وأساليبَ جديدة ليكون قريبًا منا أكثر. 
	</p>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_11/canvas-javascript.png.d935f4eb9d74e797866e2f52214c1c7f.png"><img alt="canvas-javascript.thumb.png.de602dc063e7" class="ipsImage ipsImage_thumbnailed" data-fileid="7930" src="https://academy.hsoub.com/uploads/monthly_2015_11/canvas-javascript.thumb.png.de602dc063e7479fa5ee3d539bb21699.png"></a>
	</p>

	<p>
		نحنُ كمطوري ويب بحاجة دائمًا إلى إضافةِ لمساتٍ ساحرة وتصاميمَ مبتكرة لإنعاش موقع الويب والتفرّد بعنصر الإبداع في إظهار الموقع بأبهى حلّة وأجمل تصميم.
	</p>
</div>

<div id="wmd-preview-section-20">
	<p>
		سأضع بين يديك مقدمة لأهم خيارين قد يختار منهما مطوّر الويب عند الشروع في بناء وتصميم محتوى وعناصر موقع الويب.
	</p>

	<p>
		الخيار أو الأسلوب الأوّل وهو الأكثر شهرة بحكم قدمه هو العمل مع عناصر DOM في HTML هذا النهج الذي تستخدمه أنت و 99% من المطورين في العالم الذي يعتمد على إنشاء HTML ،CSS، و JavaScript ليكون لديك عناصر ورسومات تُظهرها بإبداعك الخاص.
	</p>

	<p>
		النهج الثاني والذي ظهر بظهور HTML5 وهو استخدام عنصر <span style="font-family:courier new,courier,monospace;">&lt;canvas&gt;</span>. والذي يتيح لك أن تجرب وتتخيل الرسم بطريقةٍ أخرى وأكثر متعة غير تلك التي ألِفناها.
	</p>

	<p>
		إنّ كُلًّا من هذين الخيارين له استخدامه الخاص الذي يعتمد بالدرجة الأولى على درجةِ تعقيدِ عنصر التصميم الذي تودُّ إنشاءه، سأقوم بعرض لمحة سريعة عن الفروقات بين المنهجيتين واستخدام كل منهما.
	</p>

	<p>
		إن عملية ترجمة محتوى الصفحة وإظهارها على المتصفّح تسير وفق نظامين هما نظام وضع الاحتفاظ (retained mode (Dom والنظام الحالي أو الفوري (Immediate Mode (canvas.
	</p>
</div>

<div id="wmd-preview-section-21">
	<h2 id="نظام-وضع-الاحتفاظ-dom">
		نظام وضع الاحتفاظ (Dom)
	</h2>

	<p>
		في هذا النظام تقوم بإرسال العناصر والمحتويات التي قمتَ بإنشائها إلى Graphics <abbr title="واجهة برمجية | Application Programming Interface">API</abbr> والذي بدوره يقوم بإظهارها على المتصفّح.
	</p>

	<p>
		في الشكل التالي توضيح لكيفية حدوث نظام وضع الاحتفاظ retained mode:
	</p>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_11/565619920b656__1.png.a50e63e756691969b12a90bb78c09302.png"><img alt="5656199274a04__1.thumb.png.e34e48454b8a0" class="ipsImage ipsImage_thumbnailed" data-fileid="7917" src="https://academy.hsoub.com/uploads/monthly_2015_11/5656199274a04__1.thumb.png.e34e48454b8a0c9bc0521c3c3ff96516.png"></a>
	</p>
</div>

<div id="wmd-preview-section-22">
	<h2 id="النظام-الحالي-أو-الفوري-canvas">
		النظام الحالي أو الفوري (Canvas)
	</h2>

	<p>
		النظام الفوري أو الحالي الذي يعتمد على استخدام <span style="font-family:courier new,courier,monospace;">&lt;canvas&gt;</span> يتمتع بلياقة عالية تجعله أهلًا لرفع الأحمال الثقيلة heavy lifting فإنك لا تقوم بتحديد ما ستود رسمه فقط بل تقوم بإنشاء وصيانة التصميم أي أن Graphics <abbr title="واجهة برمجية | Application Programming Interface">API</abbr> الذي قام بالكثير من أجلك في نظام وضع الاحتفاظ retained mode لا يقوم بالشيء الكثير هنا.
	</p>

	<p>
		في الشكل التالي توضيح لكيفية حدوث النظام الفوري أو الحالي Immediate mode:
	</p>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_11/56561994df7fe__2.png.24d461e241148a0cbf289f628c446ed7.png"><img alt="565619954723d__2.thumb.png.7c962d8aa01d8" class="ipsImage ipsImage_thumbnailed" data-fileid="7918" src="https://academy.hsoub.com/uploads/monthly_2015_11/565619954723d__2.thumb.png.7c962d8aa01d87e1abbbba89cdcaef49.png"></a>
	</p>

	<p>
		بمجمل الأحوال فإن استخدام عنصر <span style="font-family:courier new,courier,monospace;">&lt;canvas&gt;</span> أسرع بكثير من استخدام نظام وضع الاحتفاظ retained mode كما أنه يوفّر مرونة كبيرة مقارنة بوضع الاحتفاظ وخاصة في التّعامل مع عناصر كثيرة. توجد سيئة واحدة في استخدام <span style="font-family:courier new,courier,monospace;">&lt;canvas&gt; </span>وهي في حال العمل على مساحة واسعة سيكون هناك نوعًا من البطء في الأداء.
	</p>

	<p>
		لا يمكنك تخيل ما قد تستطيع عمله في هذه الأداة فبإمكانك القيام برسومات بيانية، إنشاء رسوم بتأثيرات حركية Animations وعمل تراكيب صور photo Compositions أو حتى القيام بمعالجة الفيديو.
	</p>

	<p>
		تدعم Canvas جميع المُتصّفحات الحديثة: 
	</p>

	<ul><li>
			فيرفكس (الإصدار 1.5 وما فوق).
		</li>
		<li>
			safari و OS X Dashboard (على نظام ماك).
		</li>
		<li>
			IE (الإصدار 9 وما فوق).
		</li>
		<li>
			Chrome و Opera.
		</li>
	</ul><p>
		لنبدأ الآن بالتعرف على عنصر <span style="font-family:courier new,courier,monospace;">&lt;canvas&gt; </span>عن قرب وتَعلُّم كيفيّة إنشاء سياق لوحة ثنائي الأبعاد وتقوم برسم أول مثال لك على متصفّحك.
	</p>
</div>

<div id="wmd-preview-section-23">
	<h2 id="الرقعة-canvas">
		الرقعة Canvas
	</h2>

	<p>
		يبدو لنا للوهلة الأولى أن عنصر<span style="font-family:courier new,courier,monospace;"> &lt;canvas&gt;</span> يشبه عنصر <span style="font-family:courier new,courier,monospace;">&lt;img&gt;</span> مع فارق واضح وكبير هو أن عنصر <span style="font-family:courier new,courier,monospace;">&lt;canvas&gt;</span> ليس لديه خاصيّة <span style="font-family:courier new,courier,monospace;">src</span> و <span style="font-family:courier new,courier,monospace;">alt</span>.
	</p>

	<p>
		عنصر <span style="font-family:courier new,courier,monospace;">&lt;canvas&gt;</span> لديه خاصيتان وحيدتان فقط هما العرض <span style="font-family:courier new,courier,monospace;">width</span> والطول <span style="font-family:courier new,courier,monospace;">height</span>، القيم الافتراضية هي 300 بكسل للعرض و 150 بكسل للطول.
	</p>

	<p>
		ككل عناصر HTML فإن عنصر <span style="font-family:courier new,courier,monospace;">&lt;canvas&gt;</span> يعرف كوسم:
	</p>

	<pre class="html ipsCode prettyprint prettyprinted" data-pbcklang="html" data-pbcktabsize="4">
<span class="tag">&lt;canvas</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"tutorial"</span><span class="pln"> </span><span class="atn">width</span><span class="pun">=</span><span class="atv">"150"</span><span class="pln"> </span><span class="atn">height</span><span class="pun">=</span><span class="atv">"150"</span><span class="tag">&gt;</span><span class="pln">
</span><span class="tag">&lt;/canvas&gt;</span></pre>

	<p>
		لا تعتبر الخاصيّة <span style="font-family:courier new,courier,monospace;">id</span> خاصيّة محددة بالرُّقعة <span style="font-family:courier new,courier,monospace;">&lt;canvas&gt;</span> ولكنها واحدة من الخصائص العامة لـHTML <a href="http://www.w3schools.com/tags/ref_standardattributes.asp" rel="external nofollow">global Html attribute</a>.
	</p>
</div>

<div id="wmd-preview-section-24">
	<p>
		يمكن تصميم عنصر <span style="font-family:courier new,courier,monospace;">&lt;canvas&gt;</span> كأي عنصر صورة image وتحديد الخصائص مثل (margin ،border ،background، ...) مثل هذه الخصائص لا تؤثر على عملية الرسم الفعلي هي فقط تحدد الشكل العام للوحة <span style="font-family:courier new,courier,monospace;">&lt;canvas&gt;</span>.
	</p>
</div>

<div id="wmd-preview-section-25">
	<h2 id="المحتوى-الاحتياطي-fallback-content">
		المحتوى الاحتياطي Fallback Content
	</h2>

	<p>
		بالرّغم من أنه لا يتم إظهار أو تشغيل عنصر Canvas في المتصفّحات غير الداعمة للـ HTML5 إلا أنه يمكنك إنشاء محتوى احتياطي fallback content ليحل محل <span style="font-family:courier new,courier,monospace;">&lt;canvas&gt;</span> في المتصفّحات ذات الإصدارات القديمة نوعًا ما والتي لا تدعم HTML5 مثل إصدارات Internet Explorer IE السابقة للإصدار 9.
	</p>

	<p>
		يجب أن توفر دائمًا محتوى احتياطي في حال استخدامك لعنصر الرُّقعة <span style="font-family:courier new,courier,monospace;">&lt;canvas&gt; </span>ليتم إظهارها على جميع أنواع وإصدارات المتصفّحات التي لا تدعمها.
	</p>

	<p>
		لتوفير محتوى احتياطي ستحتاج إلى إضافة نص أو صورة داخل وسم <span style="font-family:courier new,courier,monospace;">&lt;canvas&gt;</span> بحيث حين يتم تشغيل الصفحة في متصفّح لا يدعم Canvas سيقوم المتصفّح بتجاهل العنصر الحاوي على المحتوى الاحتياطي وهو عنصر canvas ومن ثم إظهار المحتوى الاحتياطي الذي بداخلها. 
	</p>

	<p>
		أما في حال دعم المتصفّح لعنصر Canvas فسيقوم بتجاهل المحتوى الاحتياطي ويقوم بعمل rendering تصيير لعنصر <span style="font-family:courier new,courier,monospace;">&lt;canvas&gt;</span> بشكل طبيعي.
	</p>

	<p>
		على سبيل المثال لنقم بإنشاء <span style="font-family:courier new,courier,monospace;">&lt;canvas&gt;</span> وتوفير محتوى احتياطي لها، سأقوم بعمل محتوى احتياطي عبارة عن نص وكذلك مثال آخر يكون المحتوى الاحتياطي فيه عبارة عن صورة <span style="font-family:courier new,courier,monospace;">&lt;img&gt;</span>:
	</p>

	<pre class="html ipsCode prettyprint prettyprinted" data-pbcklang="html" data-pbcktabsize="4">
<span class="tag">&lt;canvas</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"stockGraph"</span><span class="pln"> </span><span class="atn">width</span><span class="pun">=</span><span class="atv">"150"</span><span class="pln"> </span><span class="atn">height</span><span class="pun">=</span><span class="atv">"150"</span><span class="tag">&gt;</span><span class="pln"> 
    current stock price: $3.15 +0.15 
</span><span class="tag">&lt;/canvas&gt;</span><span class="pln"> 
</span><span class="tag">&lt;canvas</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"clock"</span><span class="pln"> </span><span class="atn">width</span><span class="pun">=</span><span class="atv">"150"</span><span class="pln"> </span><span class="atn">height</span><span class="pun">=</span><span class="atv">"150"</span><span class="tag">&gt;</span><span class="pln"> 
    </span><span class="tag">&lt;img</span><span class="pln"> </span><span class="atn">src</span><span class="pun">=</span><span class="atv">"images/clock.png"</span><span class="pln"> </span><span class="atn">width</span><span class="pun">=</span><span class="atv">"150"</span><span class="pln"> </span><span class="atn">height</span><span class="pun">=</span><span class="atv">"150"</span><span class="pln"> </span><span class="atn">alt</span><span class="pun">=</span><span class="atv">""</span><span class="tag">/&gt;</span><span class="pln"> 
</span><span class="tag">&lt;/canvas&gt;</span></pre>
</div>

<div id="wmd-preview-section-27">
	<h3 id="1-وسم-الإغلاق-canvas">
		وسم الإغلاق &lt;/canvas&gt;
	</h3>

	<p>
		لا بد أنك لاحظت أن الوسم <span style="font-family:courier new,courier,monospace;">&lt;img&gt;</span> مثلًا لا يتطلب وسم إغلاق ولا تتأثر بذلك باقي العناصر، عنصر في حين أن عنصر canvas يحتاج لوضع وسم الإغلاق <span style="font-family:courier new,courier,monospace;">&lt;/canvas&gt;</span> هو وسم مطلوب required وذلك لأنه في حال عدم وضعه سيتم اعتبار كل شيء في الصفحة بعد الوسم <span style="font-family:courier new,courier,monospace;">&lt;canvas&gt;</span> هو عبارة عن محتوى احتياطي ولن يتم إظهاره.
	</p>
</div>

<div id="wmd-preview-section-28">
	<h2 id="سياق-التصيير-the-rendering-context">
		سياق التصيير The rendering Context
	</h2>

	<p>
		يقوم عنصر <span style="font-family:courier new,courier,monospace;">&lt;canvas&gt;</span> بإنشاء سطح ذو قياس ثابت يتسع لأكثر من سياق تصيير rendering context التي يتم استخدامها لإنشاء والتعامل مع المحتوى المعروض.
	</p>

	<p>
		سنركز هنا على سياق التصيير ثنائي الأبعاد 2D rendering context.
	</p>

	<p>
		يوجد سياقات أخرى توفر أنواعًا مختلفة من التصيير rendering مثل السياق ثلاثي الأبعاد <a href="https://en.wikipedia.org/wiki/WebGL" rel="external nofollow">WebGL</a> الذي يرتكز على OpenGL ES.
	</p>

	<p>
		بطبيعة الحال عند إنشاء <span style="font-family:courier new,courier,monospace;">&lt;canvas&gt;</span> ستكون فارغة ولإظهار شيء فإن السكربت يحتاج للوصول إلى سياق التصيير Rendering Context والرسم عليه. 
	</p>

	<p>
		عنصر <span style="font-family:courier new,courier,monospace;">&lt;canvas&gt; </span>يحتوى على دالة method تسمى <span style="font-family:courier new,courier,monospace;">()getContext</span> تستَخدم لتطبيق سياق التصيير Rendering Context ودوال الرسم الخاصة به، تأخذ الدالة <span style="font-family: 'courier new', courier, monospace; line-height: 24.8889px;">()getContext </span>معاملًا واحدًا one parameter وهو نوع السياق، للرسومات ثنائية الأبعاد 2D Graphics نقوم بتحديد “2d” لنحصل على سياق تصيير ثنائي الأبعاد Canvas RenderingContext2D.
	</p>

	<p>
		كما في المثال التالي:
	</p>

	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4">
<span class="kwd">var</span><span class="pln"> canvas </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'tutorial'</span><span class="pun">);</span><span class="pln"> 
</span><span class="kwd">var</span><span class="pln"> ctx </span><span class="pun">=</span><span class="pln"> canvas</span><span class="pun">.</span><span class="pln">getContext</span><span class="pun">(</span><span class="str">'2d'</span><span class="pun">);</span></pre>

	<p>
		يجلب السطر الأول من السكربت العنصر <span style="font-family: 'courier new', courier, monospace; line-height: 24.8889px;">&lt;canvas&gt;</span> من خلال استدعاء الدالة <span style="font-family:courier new,courier,monospace;">()document.getElementById</span>، ثم تحديد نوع السياق عن طريق الدالة <span style="font-family:courier new,courier,monospace;">()getContext</span>.
	</p>
</div>

<div id="wmd-preview-section-30">
	<h2 id="التأكد-من-الدعم-checking-for-support">
		التأكد من الدعم Checking for support
	</h2>

	<p>
		شرحنا في البداية أن المحتوى الاحتياطي يظهر في المتصفّحات التي لا تدعم عنصر <span style="font-family: 'courier new', courier, monospace; line-height: 24.8889px;">&lt;canvas&gt;</span> يمكن أيضًا للسكربت أن يقوم بالتأكُّد من الدّعم برمجيًا من خلال اختبار بسيط لوجود الدالة <span style="font-family:courier new,courier,monospace;">()getContext.</span>
	</p>

	<p>
		لنقم بتعديل الشيفرة البرمجية أعلاه ونستخدم السكربت في التأكد من دعم المتصفّح لعنصر <span style="font-family: 'courier new', courier, monospace; line-height: 24.8889px;">&lt;canvas&gt;</span> ليصبح على النحو التالي:
	</p>

	<pre class="javascript ipsCode prettyprint prettyprinted" data-pbcklang="javascript" data-pbcktabsize="4">
<span class="kwd">var</span><span class="pln"> canvas </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'tutorial'</span><span class="pun">);</span><span class="pln"> 
</span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">canvas</span><span class="pun">.</span><span class="pln">getContext</span><span class="pun">){</span><span class="pln"> 
    </span><span class="kwd">var</span><span class="pln"> ctx </span><span class="pun">=</span><span class="pln"> canvas</span><span class="pun">.</span><span class="pln">getContext</span><span class="pun">(</span><span class="str">'2d'</span><span class="pun">);</span><span class="pln"> 
    </span><span class="com">// drawing code here </span><span class="pln">
</span><span class="pun">}</span><span class="pln"> 
</span><span class="kwd">else</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
    </span><span class="com">// &lt;canvas&gt; unsupported code here </span><span class="pln">
</span><span class="pun">}</span></pre>
</div>

<div id="wmd-preview-section-32">
	<h2 id="قالب-الهيكل-skeleton-template">
		قالب الهيكل Skeleton Template
	</h2>

	<p>
		سأقوم ببناء قالب أساسي لاستخدامه كنقطة انطلاق لأمثلتنا اللاحقة. 
	</p>

	<p>
		<strong>ملاحظة:</strong> ليس من الأمور الجيدة تضمين السكربت في وسم HTML ولكن قمت بذلك للحفاظ على المثال موجز ومختصر.
	</p>

	<pre class="html ipsCode prettyprint prettyprinted" data-pbcklang="html" data-pbcktabsize="4">
<span class="dec">&lt;!DOCTYPE html&gt;</span><span class="pln"> 
</span><span class="tag">&lt;html&gt;</span><span class="pln"> 
  </span><span class="tag">&lt;head&gt;</span><span class="pln"> 
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">charset</span><span class="pun">=</span><span class="atv">"utf-8"</span><span class="tag">/&gt;</span><span class="pln"> 
    </span><span class="tag">&lt;title&gt;</span><span class="pln">canvas tutorial</span><span class="tag">&lt;/title&gt;</span><span class="pln"> 
    </span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text/javascript"</span><span class="tag">&gt;</span><span class="pln">       
      </span><span class="kwd">function</span><span class="pln"> draw</span><span class="pun">(){</span><span class="pln"> 
        </span><span class="kwd">var</span><span class="pln"> canvas </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">'tutorial'</span><span class="pun">);</span><span class="pln"> 
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">canvas</span><span class="pun">.</span><span class="pln">getContext</span><span class="pun">){</span><span class="pln"> 
          </span><span class="kwd">var</span><span class="pln"> ctx </span><span class="pun">=</span><span class="pln"> canvas</span><span class="pun">.</span><span class="pln">getContext</span><span class="pun">(</span><span class="str">'2d'</span><span class="pun">);</span><span class="pln"> 
        </span><span class="pun">}</span><span class="pln"> 
      </span><span class="pun">}</span><span class="pln"> 
    </span><span class="tag">&lt;/script&gt;</span><span class="pln"> 
    </span><span class="tag">&lt;style</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"text/css"</span><span class="tag">&gt;</span><span class="pln"> canvas </span><span class="pun">{</span><span class="pln"> border</span><span class="pun">:</span><span class="pln"> </span><span class="lit">1px</span><span class="pln"> solid black</span><span class="pun">;</span><span class="pln"> </span><span class="pun">}</span><span class="pln"> </span><span class="tag">&lt;/style&gt;</span><span class="pln"> 
  </span><span class="tag">&lt;/head&gt;</span><span class="pln"> 
  </span><span class="tag">&lt;body</span><span class="pln"> </span><span class="atn">onload</span><span class="pun">=</span><span class="atv">"</span><span class="pln">draw</span><span class="pun">();</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln"> 
    </span><span class="tag">&lt;canvas</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"tutorial"</span><span class="pln"> </span><span class="atn">width</span><span class="pun">=</span><span class="atv">"150"</span><span class="pln"> </span><span class="atn">height</span><span class="pun">=</span><span class="atv">"150"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;/canvas&gt;</span><span class="pln"> 
  </span><span class="tag">&lt;/body&gt;</span><span class="pln"> 
</span><span class="tag">&lt;/html&gt;</span></pre>
</div>

<div id="wmd-preview-section-33">
	<p>
		يحتوي السكربت على دالة تدعى<span style="font-family:courier new,courier,monospace;"> ()draw</span> التي تُنّفذ في حين الانتهاء من تحميل صفحة الويب، يتم ذلك عن طريق الاستماع للحدث load في الصفحة حيث يتم استدعاءه باستخدام <span style="font-family:courier new,courier,monospace;">()window.setTimeout </span>و ()<span style="font-family:courier new,courier,monospace;">window.setInterval</span> أو أي معالج حدث آخر event handler طالما أنه يتم تحميل الصفحة أولًا.
	</p>

	<p>
		عند تنفيذ السكربت أعلاه سيظهر لنا الشكل التالي في صفحة الويب:
	</p>

	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_11/5656199737da9__3.png.05750b58aa8cac672c63b4554608f3a3.png" style="line-height: 24.8889px; text-align: center;"><img alt="56561997393ad__3.thumb.png.ce6cbf2736372" class="ipsImage ipsImage_thumbnailed" data-fileid="7919" src="https://academy.hsoub.com/uploads/monthly_2015_11/56561997393ad__3.thumb.png.ce6cbf2736372ebcfacf2f731075ea32.png"></a>
	</p>
</div>

<div id="wmd-preview-section-34">
	<h2 id="تطبيق-مثال-بسيط">
		تطبيق مثال بسيط
	</h2>

	<p>
		دعونا نلقي نظرة على مثال بسيط يقوم برسم مستطيلين متقاطعين أحدهما يحوي على شفافية لونية alpha transparency.
	</p>

	<pre class="html ipsCode prettyprint prettyprinted" data-pbcklang="html" data-pbcktabsize="4">
<span class="dec">&lt;!DOCTYPE html&gt;</span><span class="pln"> 
</span><span class="tag">&lt;html&gt;</span><span class="pln"> 
  </span><span class="tag">&lt;head&gt;</span><span class="pln"> 
    </span><span class="tag">&lt;meta</span><span class="pln"> </span><span class="atn">charset</span><span class="pun">=</span><span class="atv">"utf-8"</span><span class="tag">/&gt;</span><span class="pln"> 
    </span><span class="tag">&lt;script</span><span class="pln"> </span><span class="atn">type</span><span class="pun">=</span><span class="atv">"application/javascript"</span><span class="tag">&gt;</span><span class="pln"> 
      </span><span class="kwd">function</span><span class="pln"> draw</span><span class="pun">()</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
        </span><span class="kwd">var</span><span class="pln"> canvas </span><span class="pun">=</span><span class="pln"> document</span><span class="pun">.</span><span class="pln">getElementById</span><span class="pun">(</span><span class="str">"canvas"</span><span class="pun">);</span><span class="pln"> 
        </span><span class="kwd">if</span><span class="pln"> </span><span class="pun">(</span><span class="pln">canvas</span><span class="pun">.</span><span class="pln">getContext</span><span class="pun">)</span><span class="pln"> </span><span class="pun">{</span><span class="pln"> 
          </span><span class="kwd">var</span><span class="pln"> ctx </span><span class="pun">=</span><span class="pln"> canvas</span><span class="pun">.</span><span class="pln">getContext</span><span class="pun">(</span><span class="str">"2d"</span><span class="pun">);</span><span class="pln"> 
          ctx</span><span class="pun">.</span><span class="pln">fillStyle </span><span class="pun">=</span><span class="pln"> </span><span class="str">"rgb(200,0,0)"</span><span class="pun">;</span><span class="pln"> 
          ctx</span><span class="pun">.</span><span class="pln">fillRect </span><span class="pun">(</span><span class="lit">10</span><span class="pun">,</span><span class="pln"> </span><span class="lit">10</span><span class="pun">,</span><span class="pln"> </span><span class="lit">55</span><span class="pun">,</span><span class="pln"> </span><span class="lit">50</span><span class="pun">);</span><span class="pln"> 
          ctx</span><span class="pun">.</span><span class="pln">fillStyle </span><span class="pun">=</span><span class="pln"> </span><span class="str">"rgba(0, 0, 200, 0.5)"</span><span class="pun">;</span><span class="pln"> 
          ctx</span><span class="pun">.</span><span class="pln">fillRect </span><span class="pun">(</span><span class="lit">30</span><span class="pun">,</span><span class="pln"> </span><span class="lit">30</span><span class="pun">,</span><span class="pln"> </span><span class="lit">55</span><span class="pun">,</span><span class="pln"> </span><span class="lit">50</span><span class="pun">);</span><span class="pln"> 
        </span><span class="pun">}</span><span class="pln"> 
      </span><span class="pun">}</span><span class="pln"> 
    </span><span class="tag">&lt;/script&gt;</span><span class="pln"> 
  </span><span class="tag">&lt;/head&gt;</span><span class="pln"> 
  </span><span class="tag">&lt;body</span><span class="pln"> </span><span class="atn">onload</span><span class="pun">=</span><span class="atv">"</span><span class="pln">draw</span><span class="pun">();</span><span class="atv">"</span><span class="tag">&gt;</span><span class="pln"> 
    </span><span class="tag">&lt;canvas</span><span class="pln"> </span><span class="atn">id</span><span class="pun">=</span><span class="atv">"canvas"</span><span class="pln"> </span><span class="atn">width</span><span class="pun">=</span><span class="atv">"150"</span><span class="pln"> </span><span class="atn">height</span><span class="pun">=</span><span class="atv">"150"</span><span class="tag">&gt;</span><span class="pln">
    </span><span class="tag">&lt;/canvas&gt;</span><span class="pln"> 
  </span><span class="tag">&lt;/body&gt;</span><span class="pln"> 
</span><span class="tag">&lt;/html&gt;</span></pre>
</div>

<div id="wmd-preview-section-35">
	<p style="text-align: center;">
		<a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_11/56561999193fa__4.png.3fa575eeb42a12516bd900a9371d6ec4.png"><img alt="565619991ac2b__4.thumb.png.6b43e8fcf1e63" class="ipsImage ipsImage_thumbnailed" data-fileid="7920" src="https://academy.hsoub.com/uploads/monthly_2015_11/565619991ac2b__4.thumb.png.6b43e8fcf1e63eb507d268d73f755591.png"></a>
	</p>

	<p>
		اعتمادًا على القالب الأساسي الذي أنشأتُه وضعت السكربت الخاص باستخدام سياق التصيير<span style="font-family:courier new,courier,monospace;"> ()Rendering Context getContext</span> ضمن الشرط <span style="font-family:courier new,courier,monospace;">if</span> وذلك ليتم تنفيذه في حال تحقق وجود دعم للعنصر <span style="font-family:courier new,courier,monospace;">&lt;canvas&gt;</span> من قِبل المتصفّح. 
	</p>

	<p>
		تقوم الدالة<span style="font-family:courier new,courier,monospace;"> ()getContext</span> بإرجاع متغير يمكن اعتباره غرض object يحوي على مجموعة دوال تقوم بعمليات الرسم وإنشاء الأشكال. 
	</p>

	<p>
		الخاصيّة <span style="font-family:courier new,courier,monospace;">fillStyle</span> تقوم بتحديد اللّون الذي سيتم به تلوين العنصر التالي، تأخذ الخاصيّة <span style="font-family:courier new,courier,monospace;">fillStyle</span> اللّون بنظام (RGB (Red, Green, Blue والشفافية opacity.
	</p>

	<p>
		لاحظ أنه تم تلوين المستطيل الأول باللون الأحمر حيث أخذ قيمة 200 في حقل red، والمستطيل الثاني بلون أزرق مع تحديد الشفافية opacity=0.5 أي سيكون ذو شفافية لونية بنسبة 50% (تأخذ الخاصيّة opacity قيمها من 0.0 -1.0).
	</p>

	<p>
		الدالة<span style="font-family:courier new,courier,monospace;"> ()FillRect</span> ترسم مستطيل ذو مساحة لونية كاملة solid color وذلك بتحديد إحداثيات النقاط الأربع للمستطيل الذي نود رسمه ابتداءً من الزاوية اليسارية العليا التي تأخذ احداثيات المركز (0,0).
	</p>

	<p>
		كانت هذه أبرز النقاط التي تحيطك بالمفاهيم الأساسية لاستخدام عنصر <span style="font-family:courier new,courier,monospace;">canvas</span> في <a href="https://academy.hsoub.com/search/?tags=js+canvas+101">الدروس المقبلة</a> ستكون الشروحات غنية للغاية وسترى إمكانيات مذهلة لعنصر canvas تشحذ أفكارك الابداعية بامتياز.
	</p>

	<p>
		<a href="https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API" rel="external nofollow">المصادر</a>
	</p>
</div>
]]></description><guid isPermaLink="false">207</guid><pubDate>Wed, 25 Nov 2015 20:58:00 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641;&#x64A;&#x629; &#x627;&#x644;&#x640;&#x62A;&#x639;&#x627;&#x645;&#x644; &#x645;&#x639; &#x62E;&#x631;&#x627;&#x626;&#x637; Google Maps &#x628;&#x631;&#x645;&#x62C;&#x64A;&#x627; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A; (&#x627;&#x644;&#x640;&#x62C;&#x632;&#x621; &#x627;&#x644;&#x62B;&#x627;&#x646;&#x64A;)</title><link>https://academy.hsoub.com/programming/javascript/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D9%84%D9%80%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%AE%D8%B1%D8%A7%D8%A6%D8%B7-google-maps-%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A7-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-%D8%A7%D9%84%D9%80%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%AB%D8%A7%D9%86%D9%8A-r187/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_10/google-maps.thumb.png.2a3d62db65a54acaace85e89b6b7b85f.png.90bde532ffcfac8ab50d86962cd877a6.png" /></p>

<div id="wmd-preview-section-114"><p id="كيفية-الـتعامل-مع-خرائط-google-maps-برمجيا-باستخدام-جافاسكربت-الـجزء-الثاني">تناولنا في المقال السابق <a href="https://academy.hsoub.com/programming/javascript/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D9%84%D9%80%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%AE%D8%B1%D8%A7%D8%A6%D8%B7-google-maps-%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A7-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-%D8%A7%D9%84%D9%80%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%A3%D9%88%D9%84-r181/">أساسيات التعامل مع مكتبة Google Maps JavaScript <abbr title="واجهة برمجية | Application Programming Interface">API</abbr></a> لإنشاء الخرائط والرسم عليها والتفاعل معها مثل خاصية النقر على الخريطة وتحديد الأماكن.</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/google-maps.thumb.png.2a3d62db65a54acaace85e89b6b7b85f.png.73ef88283048de4827548140337b93f3.png"><img data-fileid="5702" class="ipsImage ipsImage_thumbnailed" alt="google-maps.thumb.png.2a3d62db65a54acaac" src="https://academy.hsoub.com/uploads/monthly_2015_10/google-maps.thumb.png.2a3d62db65a54acaace85e89b6b7b85f.thumb.png.b69fdef878833545a493da54be460e27.png"></a></p><p>في هذا المقال سأتوسع في الشرح عن أنواع خرائط غوغل وخصائص كل نوع وعن كيفيّة رسم أشكال قابلة للتعديل والسحب على الخريطة، بالإضافة إلى خدمة street view منظور الشارع التي تتيح لك رؤية تفاصيل طرق وشوارع منطقتك، وسأختم بالحديث عن أهم وأكثر الخدمات المستخدمة وهي خدمة تحديد المواقع Geolocation.</p></div><div id="wmd-preview-section-115"><h2 id="أنواع-الخرائط-maps-type">أنواع الخرائط Maps Type</h2><p>تُوفّر مكتبة غوغل أربع أنواع خرائط رئيسية:</p><ul><li><strong>ROADMAP</strong> ( الخريطة اإفتراضية العادية 2D map ).</li><li><strong>SATELLITE</strong> (خريطة مصورة).</li><li><strong>HYBRID</strong> (خريطة مصورة بالإضافة إلى أسماء الطرق والمدن).</li><li><strong>TERRAIN</strong> (خريطة تضمن الجبال والأنهار…الخ).</li></ul><p>يمكنك تحديد نوع الخريطة عن طريق الخاصية <span style="font-family:courier new,courier,monospace;">mapTypeId</span> كما شرحنا في الدرس السابق. حيث يمكنك تحديدها إما عن طريق الـ Constructor المنشئ <br>كما في الشيفرة التّالية:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">var myLatlng = new google.maps.LatLng(-34.397, 150.644); 
var mapOptions = { 
    zoom: 8, 
    center: myLatlng, 
    mapTypeId: google.maps.MapTypeId.SATELLITE 
}; 
var map = new google.maps.Map(document.getElementById("map"), mapOptions);</pre><p>أو تعديلها عن طريق الدالة <span style="font-family:courier new,courier,monospace;">setMapTypeId</span>:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">map.setMapTypeId(google.maps.MapTypeId.TERRAIN);</pre><h3>الخريطة المصورة SATELLITE</h3><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/5617fa80babf7___1.png.4a6eedc5563afc5d1680e9e66bb7ab52.png"><img data-fileid="5684" class="ipsImage ipsImage_thumbnailed" alt="5617fa814ba95___1.thumb.png.2df70556c47c" src="https://academy.hsoub.com/uploads/monthly_2015_10/5617fa814ba95___1.thumb.png.2df70556c47c80b5064b8f95005b69c7.png"></a></p></div><div id="wmd-preview-section-117"><h3>الخريطة المصورة مع أسماء المدن والطرق HYBRID</h3><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/5617fa98af153___2.png.22060406ffd1eeac29a87cf2735abc9f.png"><img data-fileid="5685" class="ipsImage ipsImage_thumbnailed" alt="5617fa9921e5e___2.thumb.png.8ab16202cfa4" src="https://academy.hsoub.com/uploads/monthly_2015_10/5617fa9921e5e___2.thumb.png.8ab16202cfa45d55009eec7575c431a2.png"></a></p><h3>الخريطة الجغرافية تتضمن جبال وأنهار.. الخ TERRAIN </h3><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/5617fb3755cf8___3.png.ed5e6833963f367d6c2dc45240e90ca3.png"><img data-fileid="5686" class="ipsImage ipsImage_thumbnailed" alt="5617fb37f4153___3.thumb.png.d8965acf5b51" src="https://academy.hsoub.com/uploads/monthly_2015_10/5617fb37f4153___3.thumb.png.d8965acf5b5180384a63ac373d053a20.png"></a></p></div><div id="wmd-preview-section-118"><h2 id="الخريطة-التصويرية-منظور-45-imagery">الخريطة التصويرية منظور 45° Imagery</h2></div><div id="wmd-preview-section-119"><h3 id="1-منظور-45-imagery">1. منظور 45° Imagery</h3><p>تتيح لك مكتبة غوغل إنشاء خريطة تصويرية بدقة عالية من منظور جغرافي معين، أنواع الخرائط التي تدعم الخريطة التصويرية من منظور 45 درجة  هما: SATELLITE و HYBRID. يجب أن تكون قيمة التكبير zoom عالية أي أكثر من 17 لكي يظهر المنظور واضحًا. </p><p>سأعرض الآن خريطتين لنفس المكان الأولى بدون خاصية منظور 45° درجة والأخرى مع خاصية منظور. </p><p>لقد لاحظت من تجربتي أن هناك بعض المناطق لا تدعم خاصية المنظور مثل تركيا، لذا سيكون المثال هنا إيطاليا - فينيسيا وقصر دوجي بالتحديد:</p><ul><li><p>قصر دوجي من دون خاصية منظور 45°:</p></li></ul><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/5617fb5154d02___4.png.359d18f65b92023651af5e9069c7fad2.png"><img data-fileid="5687" class="ipsImage ipsImage_thumbnailed" alt="5617fb51a26c9___4.thumb.png.0482ffc982e3" src="https://academy.hsoub.com/uploads/monthly_2015_10/5617fb51a26c9___4.thumb.png.0482ffc982e35fc9704e87a41df24570.png"></a></p><ul><li><p>قصر دوجي مع خاصية منظور 45°:</p></li></ul><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/5617fb85ba997___5.png.35850bedc73ef8358d86ee2263d86480.png"><img data-fileid="5688" class="ipsImage ipsImage_thumbnailed" alt="5617fb866cae2___5.thumb.png.978999467703" src="https://academy.hsoub.com/uploads/monthly_2015_10/5617fb866cae2___5.thumb.png.9789994677038d232d9fe4e21376d762.png"></a></p><p>الآن لتفعيل خاصية المنظور فقط قم بإضافة:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">setTilt(45)</pre><p>أما لتعطيل الخاصية نقوم بوضع القيمة 0 بدل 45:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">setTilt(0)</pre><p>كما في الشيفرة التّالية:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">function initialize() { 
    var mapProp = { 
        center: new google.maps.LatLng(45.434046, 12.340284), 
        zoom: 18, 
        mapTypeId: google.maps.MapTypeId.SATELLITE 
    }; 
    var map = new google.maps.Map(document.getElementById("map"), mapProp); 
    map.setTilt(45); 
} 

google.maps.event.addDomListener(window, 'load', initialize);
</pre></div><div id="wmd-preview-section-123"><h3 id="2-خاصية-التدوير-في-الاتجاهات-الأربعة">2. خاصية التدوير في الاتجاهات الأربعة</h3><p>إن الخريطة التصويرية Imagery 45 تتضمن مجموعة من الصور لأربعة إتجاهات (شرق، غرب، شمال وجنوب). يمكنك تدوير المنظور تلقائيًا لتشاهد المكان من جميع الإتجاهات باستخدام الدالة<span style="font-family:courier new,courier,monospace;"> ()setHeading</span> وتمرير قيمة درجة التدوير ابتداءً من الشمال. </p><ul><li>أولًا نحدد للخاصية <span style="font-family:courier new,courier,monospace;">heading</span> القيمة 90 جهة الشمال، ونعطي القيمة 45 درجة للخاصية <span style="font-family:courier new,courier,monospace;">tilt</span> لتشغيل المنظور.</li><li>نحن الآن بحاجة إلى زر Auto Rotate لنقوم بتشغيل التدوير التلقائي عند الضغط عليه. </li><li>نعرف <span style="font-family:courier new,courier,monospace;">div</span> ونعطيه التنسيق المناسب ليظهر وسط وأعلى الخريطة ثم نقوم بإنشاء زر داخل الـ <span style="font-family:courier new,courier,monospace;">div</span> كما في الشيفرة التّالية:</li></ul><pre data-pbcklang="css" data-pbcktabsize="4" class="css ipsCode prettyprint">&lt;style type="text/css"&gt; 
#floating-panel { 
    position: absolute; 
    top: 10px; 
    left: 25%; 
    z-index: 5; 
    background-color: #fff;  
    padding: 5px; 
    border: 1px solid #999; 
    text-align: center; 
    font-family: 'Roboto','sans-serif'; 
    line-height: 30px; 
    padding-left: 10px; 
} &lt;/style&gt;</pre><p>الآن لنقم بكتابة دالة<span style="font-family:courier new,courier,monospace;"> ()rotate90</span> مهمتها هي أخذ قيمة درجة التدوير الحالية <span style="font-family:courier new,courier,monospace;">heading</span> وإضافة 90 درجة. سنستفيد من هذه الدالة عند استدعائها في كل مرة تدوير.</p></div><div id="wmd-preview-section-125"><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">function rotate90() { 
    var heading = map.getHeading() || 0; map.setHeading(heading + 90); 
}</pre><p>ثم لنكتب الدالة المسؤولة عن التدوير التلقائي التي تقوم باستدعاء الدالة <span style="font-family:courier new,courier,monospace;">()rotate90</span>، هذه الدالة هي التي ستنفذ عندما نقوم بالضغط على الزر Auto Rotate</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">function autoRotate() { 
    // Determine if we're showing aerial imagery. 
    if (map.getTilt() !== 0) { 
        window.setInterval(rotate90, 3000); 
    } 
}
</pre></div><div id="wmd-preview-section-126"><p>يمكننا التحكم بسرعة التدوير (الإنتقال بين الصور) عن طريق الدالة<span style="font-family:courier new,courier,monospace;"> window.setInterval</span> بتحديد قيمة المعامل الثاني (كلما كانت القيمة أصغر كلما كانت سرعة التدوير أكبر) تتحدد القيمة بالـmilliseconds.</p><p>لنرى الآن قصر دوجي من الإتجاهات الأربعة:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/5617fc9bb6821___6__1.png.799eafd60b702eb783261c4a99efdddc.png"><img data-fileid="5689" class="ipsImage ipsImage_thumbnailed" alt="5617fc9c17201___6__1.thumb.png.6423a0485" src="https://academy.hsoub.com/uploads/monthly_2015_10/5617fc9c17201___6__1.thumb.png.6423a0485261cca8e14b47abaedeb273.png"></a></p><p style="text-align: center;"><img data-fileid="o_1a16r3kshbav1g12bc58g2db21a" class="ipsImage ipsImage_thumbnailed" alt="" src=""></p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/5617fccdb6df3___7__2.png.ac5949f4f3ccbe3597a0f49a5d74afa8.png"><img data-fileid="5690" class="ipsImage ipsImage_thumbnailed" alt="5617fcce206e2___7__2.thumb.png.a9eda90f6" src="https://academy.hsoub.com/uploads/monthly_2015_10/5617fcce206e2___7__2.thumb.png.a9eda90f6104c13039ceed72d3778ef6.png"></a></p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/5617fd601d8fb___8__3.png.813df1d9dceca844d391369e051c2847.png"><img data-fileid="5691" class="ipsImage ipsImage_thumbnailed" alt="5617fd6075d8c___8__3.thumb.png.709bf310c" src="https://academy.hsoub.com/uploads/monthly_2015_10/5617fd6075d8c___8__3.thumb.png.709bf310cc095e96608cd02154fbe011.png"></a></p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/5617fd8fc8307___9__4.png.5453acfa97e53f9d4a95ee6b42f1470b.png"><img data-fileid="5692" class="ipsImage ipsImage_thumbnailed" alt="5617fd903e01f___9__4.thumb.png.d40112fe2" src="https://academy.hsoub.com/uploads/monthly_2015_10/5617fd903e01f___9__4.thumb.png.d40112fe2b71ce88625ceb26f76c9bdb.png"></a></p></div><div id="wmd-preview-section-127"><h2 id="إضافة-أشكال-قابلة-للتحرير-والسحب-على-الخريطة-editable-and-draggable-shapes">إضافة أشكال قابلة للتحرير والسحب على الخريطة editable and draggable shapes</h2><p>إن إضافة أشكال قابلة للتعديل والسحب تتيح للمستخدم التفاعل مع الخريطة بشكل أكبر وتحديد أماكن مختلفة بطريقته الخاصة.</p></div><div id="wmd-preview-section-128"><h3 id="1-إنشاء-شكل-قابل-للتعديل">1. إنشاء شكل قابل للتعديل</h3><p>إن أي شكل من الأشكال التي يمكن إضافتها ورسمها على الخريطة (polyline, polygon, circle) كما شرحناها في الدرس السابق يمكن أن تصبح أشكال قابلة للتعديل (تغيير حجمها، موضعها وشكلها) فقط قم بإسناد القيمة <span style="font-family:courier new,courier,monospace;">true</span> للخاصية <span style="font-family:courier new,courier,monospace;">editable</span> ضمن خصائص الشكل كما في الشيفرة التّالية:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">function initialize() { 
    var mapProp = { 
        center: new google.maps.LatLng(41.008238, 28.978359), 
        zoom: 8, 
        mapTypeId: google.maps.MapTypeId.ROADMAP 
    }; 
    var map = new google.maps.Map(document.getElementById("map"), mapProp);
 
    var flightPath = new google.maps.Circle({ 
        center: new google.maps.LatLng(41.008238, 28.978359), 
        radius: 20000, 
        strokeColor: "#0000FF", 
        strokeOpacity: 0.8, 
        strokeWeight: 2, 
        fillColor: "#045B45", 
        fillOpacity: 0.4, 
        editable: true 
    }); 

    flightPath.setMap(map); 
} 

google.maps.event.addDomListener(window, 'load', initialize);
</pre></div><div id="wmd-preview-section-129"><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/5617fda474489___10.png.fb12e5f4424259e10a9ca1721d92f02d.png"><img data-fileid="5693" class="ipsImage ipsImage_thumbnailed" alt="5617fda55408a___10.thumb.png.aab720d1f2f" src="https://academy.hsoub.com/uploads/monthly_2015_10/5617fda55408a___10.thumb.png.aab720d1f2f9e7496486c70049442a8a.png"></a></p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/5617fdb7426cb___11.png.2b00dc8c94cc17a269e61bd5f8a03005.png"><img data-fileid="5694" class="ipsImage ipsImage_thumbnailed" alt="5617fdb833afd___11.thumb.png.9d87d0582a1" src="https://academy.hsoub.com/uploads/monthly_2015_10/5617fdb833afd___11.thumb.png.9d87d0582a1f08a0e9c327837ebc6c25.png"></a></p></div><div id="wmd-preview-section-130"><h3 id="2-إنشاء-شكل-قابل-للسحب-والتحريك">2. إنشاء شكل قابل للسحب والتحريك</h3><p>يمكنك جعل الشكل قابل للسحب عن طريق تفعيل الخاصية <span style="font-family:courier new,courier,monospace;">draggable</span> ضمن خصائص الشكل. </p><p><strong>ملاحظة</strong>: في حال كنت تطبق خاصية السحب على الشكل متعدد الخطوط polyline أو على المضلع polygon فإن عليك تفعيل الخاصية <span style="font-family:courier new,courier,monospace;">geodesic</span> ليتم الإحتفاظ بالشكل الجغرافي الصحيح أثناء تحريك الشكل.</p><p>كما في الشيفرة التّالية:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">var istanbul = new google.maps.LatLng(41.008238, 28.978359); 
var antalya = new google.maps.LatLng(36.896891, 30.713323); 
var trabzon = new google.maps.LatLng(41.002697, 39.716763); 

function initialize() { 
    var mapProp = { center: istanbul, zoom: 5, mapTypeId: google.maps.MapTypeId.ROADMAP }; 
    var map = new google.maps.Map(document.getElementById("map"), mapProp); 
    var redCoords = [ istanbul, antalya, trabzon ]; 

    // إنشاء مثلث أحمر قابل للتحريك مع تفعيل الخاصية geodesic
    new google.maps.Polygon({ 
        map: map, 
        paths: redCoords, 
        strokeColor: '#FF0000', 
        strokeOpacity: 0.8, 
        strokeWeight: 2, 
        fillColor: '#FF0000', 
        fillOpacity: 0.35, 
        draggable: true, 
        geodesic: true 
     }); 
}
</pre></div><div id="wmd-preview-section-131"><p><strong>قبل التحريك:</strong></p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/5617fed1b5905___12.png.bd39b231b33eec54de35ecbdb24700c1.png"><img data-fileid="5695" class="ipsImage ipsImage_thumbnailed" alt="5617fed2aade4___12.thumb.png.32a2612af10" src="https://academy.hsoub.com/uploads/monthly_2015_10/5617fed2aade4___12.thumb.png.32a2612af1042ae4fb5e774678392e35.png"></a></p><p><strong>بعد التحريك:</strong> </p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/5617fede9acca___13.png.0f4a87250de07b9ba611e2b52eebd121.png"><img data-fileid="5696" class="ipsImage ipsImage_thumbnailed" alt="5617fedf83f5b___13.thumb.png.9c4a0380654" src="https://academy.hsoub.com/uploads/monthly_2015_10/5617fedf83f5b___13.thumb.png.9c4a0380654f2d061a2f28e6b0a19309.png"></a></p></div><div id="wmd-preview-section-132"><h2 id="منظور-الشارع-street-view">منظور الشارع Street View</h2><p>توفر مكتبة Google Maps JavaScript <abbr title="واجهة برمجية | Application Programming Interface">API</abbr> خدمة عرض الشوارع سأقوم هنا بشرح كيفية تفعيل خاصية عرض الشوارع الإفتراضية على خريطتك.</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/561800153f2b2___14.png.e37858ac3d588fb989a9c8db4be0ce4e.png"><img data-fileid="5697" class="ipsImage ipsImage_thumbnailed" alt="56180015a9610___14.thumb.png.e1b2ac31346" src="https://academy.hsoub.com/uploads/monthly_2015_10/56180015a9610___14.thumb.png.e1b2ac313468e78ee45363b35c9f80a7.png"></a></p></div><div id="wmd-preview-section-133"><h3 id="1-البانوراما-panorama">1. البانوراما Panorama:</h3><p>يتم دعم خدمة عرض الشوارع من خلال استخدام الكائن StreetViewPanorama،الذي يوفر واجهة <abbr title="واجهة برمجية | Application Programming Interface">API</abbr> لعرض الشوارع. </p><p>إن كل خريطة تحتوي على خاصية عرض شوارع إفتراضية panorama بانوراما، والتي يمكنك الحصول عليها عن طريق استدعاء الدالة للخريطة <span style="font-family:courier new,courier,monospace;">()getStreetView</span>. عند تفعيلك للخاصية <span style="font-family:courier new,courier,monospace;">streetViewControl</span> فإنك تلقائيًا تكون قد فعلت خاصية عرض الشوارع الإفتراضية.</p><p>يمكنك أيضًا إنشاء كائن <span style="font-family:courier new,courier,monospace;">StreetViewPanorama</span> خاص بك لاستخدامه بدلًا من الإفتراضي.</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">var panorama; 

function initialize() { 
    panorama = new google.maps.StreetViewPanorama(document.getElementById('map'), { 
         position: { lat: 41.008238, lng: 28.978359 }, 
         pov: { heading: 165, pitch: 0 }, 
         zoom: 1 
    }); 
} 

google.maps.event.addDomListener(window, 'load', initialize);</pre><p>سأقوم الآن بعرض الخريطة وبجانبها بانوراما (عرض الشوارع).</p></div><div id="wmd-preview-section-134"><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/5618003a56a16___15.png.7a8f0e0dbbfc4398a620661e7745cf60.png"><img data-fileid="5698" class="ipsImage ipsImage_thumbnailed" alt="5618003ace135___15.thumb.png.b7c87142195" src="https://academy.hsoub.com/uploads/monthly_2015_10/5618003ace135___15.thumb.png.b7c87142195689164228942d89d5359c.png"></a></p><p>قم بإنشاء <span style="font-family:courier new,courier,monospace;">div</span> وإعطاءه <strong>"id= "pano</strong>:</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;div id="map"&gt;&lt;/div&gt; 
&lt;div id="pano"&gt;&lt;/div&gt;</pre><p>لنقوم الآن بتحديد التنسيقات لتظهر الخريطة بجانب البانوراما كما في الشيفرة التّالية:</p><pre data-pbcklang="css" data-pbcktabsize="4" class="css ipsCode prettyprint">#map, #pano { 
    float: left; 
    height: 100%; 
    width: 45%; 
}</pre><p>نقوم الآن بتحديد إحداثيات المكان (خط الطول وخط العرض) للمكان الذي نريد إظهاره مثلاً مدينة اسطنبول، ونقوم بتحديد الخصائص للبانوراما عن طريق <span style="font-family:courier new,courier,monospace;">StrrtViewPanorama</span>:</p><p>كما في الشيفرة التّالية:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">function initialize() {
    var fenway = {lat: 42.345573, lng: -71.098326}; 
    var map = new google.maps.Map(document.getElementById('map'), { center: fenway, zoom: 14 }); 
    var panorama = new google.maps.StreetViewPanorama(document.getElementById('pano'), { 
        position: fenway, 
        pov: { heading: 34, pitch: 10 } 
    }); 

    map.setStreetView(panorama);
}
</pre></div><div id="wmd-preview-section-138"><h2 id="خدمة-تحديد-المواقع-geolocation">خدمة تحديد المواقع Geolocation</h2><p>إن خدمة تحديد المواقع تتيح لك تحديد موقع المستخدم الذي يزور موقعك مثلاً وذلك عن طريق عنوان الـIP الخاص به. إن تحديد الموقع الجغرافي يعتمد أساساً على الجهاز والمتصفح الذي يستخدمه الزائر لذا فإن هنالك بعض الأجهزة والمتصفحات لا تدعم خدمة تحديد المواقع، فلا يمكننا القول أن هذه الخدمة هي خدمة ممكنة ومتاحة دائمًا في موقعك أو تطبيق الويب الخاص بك.</p><p>تستخدم بعض المتصفحات عنوان IP لكشف مكان وجود المستخدم، وبما أن عنوان IP ليس إلا تقدير تقريبي لموقع المستخدم فلا يمكنك الإعتماد عليها في تحديد المواقع بدقة، كما أنها خدمة يمكن للمستخدم تعطيلها في المتصفح الخاص به.</p><p>لنرى الآن كيف يمكننا تحديد موقع الجهاز الخاص بنا عن طريق Geolocation.</p><p>سنقوم أولًا بأخذ الإحداثيات (خط الطول وخط العرض) للمستحدم عن طريق الدالة <span style="font-family:courier new,courier,monospace;">getCurrentPosition</span> وتخزينها بالمتغير <span style="font-family:courier new,courier,monospace;">pos:</span></p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">navigator.geolocation.getCurrentPosition(function(position) { 
     var pos = { lat: position.coords.latitude, lng: position.coords.longitude 
};
</pre></div><div id="wmd-preview-section-139"><p>وبما أن هذه الخدمة يمكن ألا يدعمها المتصفح أو أن يقوم بتعطيلها المستخدم فإن علينا أن نتأكد من أن الخاصية مفعلة أولًا:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">if (navigator.geolocation) {…………}</pre><p>في حال أن المتصفح يدعم الخدمة وأنها مفعلة يتم إظهار موقع المستخدم وإلا ستظهر رسالة خطأ ولن يتم عرض موقع المستخدم.</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">infoWindow.setPosition(pos);
      infoWindow.setContent('Location found.');
      map.setCenter(pos);
    }, function() {
      handleLocationError(true, infoWindow, map.getCenter());
    });
  } else {
    // Browser doesn't support Geolocation
    handleLocationError(false, infoWindow, map.getCenter());
  }
}

function handleLocationError(browserHasGeolocation, infoWindow, pos) {
  infoWindow.setPosition(pos);
  infoWindow.setContent(browserHasGeolocation ?
                        'Error: The Geolocation service failed.' :
                        'Error: Your browser doesn\'t support geolocation.');
}</pre><p>الآن لاحظ أن المتصفح عرض نافذة للمستخدم ليخبره بأن صفحة الويب الحالية تريد أن تعرف موقعه هل تسمح بذلك؟</p></div><div id="wmd-preview-section-141"><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/561800442b319___.png16.png.bc864dffbf75acb87992ee28b2eab15a.png"><img data-fileid="5699" class="ipsImage ipsImage_thumbnailed" alt="56180044b759d___.png16.thumb.png.b809e5d" src="https://academy.hsoub.com/uploads/monthly_2015_10/56180044b759d___.png16.thumb.png.b809e5da58481c3bcc0abb4e55de6735.png"></a></p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/5618005345bf4___17.png.773232fa6b10e1f4d06394fb1d6947c3.png"><img data-fileid="5700" class="ipsImage ipsImage_thumbnailed" alt="56180053e14e0___17.thumb.png.5e91b9b6807" src="https://academy.hsoub.com/uploads/monthly_2015_10/56180053e14e0___17.thumb.png.5e91b9b68071be134cd8e9ae88b5b340.png"></a></p><p>كانت هذه أبرز المواضيع والأدوات الأكثر شيوعاً في التعامل مع خرائط Google Maps لمن لم يسبق له استخدامها.</p></div>
]]></description><guid isPermaLink="false">187</guid><pubDate>Sat, 10 Oct 2015 08:39:32 +0000</pubDate></item><item><title>&#x643;&#x64A;&#x641;&#x64A;&#x629; &#x627;&#x644;&#x640;&#x62A;&#x639;&#x627;&#x645;&#x644; &#x645;&#x639; &#x62E;&#x631;&#x627;&#x626;&#x637; Google Maps &#x628;&#x631;&#x645;&#x62C;&#x64A;&#x627; &#x628;&#x627;&#x633;&#x62A;&#x62E;&#x62F;&#x627;&#x645; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x628;&#x62A; (&#x627;&#x644;&#x640;&#x62C;&#x632;&#x621; &#x627;&#x644;&#x623;&#x648;&#x644;)</title><link>https://academy.hsoub.com/programming/javascript/%D9%83%D9%8A%D9%81%D9%8A%D8%A9-%D8%A7%D9%84%D9%80%D8%AA%D8%B9%D8%A7%D9%85%D9%84-%D9%85%D8%B9-%D8%AE%D8%B1%D8%A7%D8%A6%D8%B7-google-maps-%D8%A8%D8%B1%D9%85%D8%AC%D9%8A%D8%A7-%D8%A8%D8%A7%D8%B3%D8%AA%D8%AE%D8%AF%D8%A7%D9%85-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D8%A8%D8%AA-%D8%A7%D9%84%D9%80%D8%AC%D8%B2%D8%A1-%D8%A7%D9%84%D8%A3%D9%88%D9%84-r181/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_10/google-maps.png.41f4788d09f078ed3bf12267b93cb40b.png" /></p>

<div id="preview-contents"><div id="wmd-preview-section-48"><p id="كيفية-الـتعامل-مع-خرائط-google-maps-برمجيا-باستخدام-جافاسكربت-الـجزء-الأول">لا يكاد يخلو أي موقع ويب من وجود خرائط Google فمن خلال وضع خريطة على الموقع الخاص بك فإنك تعطي تأثيرًا غنيًا ومستوى أعلى للتفاعل بين المستخدمين.</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/google-maps.png.cc6bef40cf9c2ea9b73ff098530cb0fb.png"><img data-fileid="5418" class="ipsImage ipsImage_thumbnailed" alt="google-maps.thumb.png.2a3d62db65a54acaac" src="https://academy.hsoub.com/uploads/monthly_2015_10/google-maps.thumb.png.2a3d62db65a54acaace85e89b6b7b85f.png"></a></p><p>سأقوم في هذا المقال بشرح كيفيّة استخدام خرائط غوغل وإضافتها إلى صفحة الويب بالإضافة إلى كيفيّة تحديد أكثر من موقع بنفس الوقت على نفس الخريطة، وشرح بعض المزايا الـتي يمكنك إضافتها إلى خريطتك.</p><p>يمكنك تحميل <a class="ipsAttachLink" href="https://academy.hsoub.com/applications/core/interface/file/attachment.php?id=5417">الملف المصدري</a> للمثال الموضح في هذا الدرس.</p></div><div id="wmd-preview-section-49"><h2 id="إستخدام-مكتبة-google-api">إستخدام مكتبة Google <abbr title="واجهة برمجية | Application Programming Interface">API</abbr></h2><p>مكتبة Google Maps <abbr title="واجهة برمجية | Application Programming Interface">API</abbr> هي عبارة عن مكتبة جافاسكربت ولنتمكن من إستخدام مكتبة Google <abbr title="واجهة برمجية | Application Programming Interface">API</abbr> قم بإضافة الـسكربت الـخاص بذلك.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;script src ="http://maps.google.com/maps/api/js?sensor=false" type="text/javascript"&gt;&lt;/script&gt;
</pre></div><div id="wmd-preview-section-51"><h2 id="إنشاء-الـخريطة">إنشاء الخريطة</h2><p>قم الآن بإنشاء <span style="font-family:courier new,courier,monospace;">div</span> بالأبعاد الـتي تريد أن تظهر بها الـخريطة وقم بإعطاءه <span style="font-family:courier new,courier,monospace;">"id="map</span>.</p><pre data-pbcklang="html" data-pbcktabsize="4" class="html ipsCode prettyprint">&lt;div id="map" style="width: 600px; height: 400px;" &gt;&lt;/div&gt;</pre><p>الآن لنقم بإنشاء السكربت لإظهار الخريطة، يجب عليك عند وضع أي خريطة أن تقوم بتحديد الإحداثيات: خط الطول <strong>longitude</strong> وخط العرض <strong>latitude</strong> ضمن الخاصية <span style="font-family:courier new,courier,monospace;">center.</span></p></div><div id="wmd-preview-section-52"><p>يمكنك معرفة الإحداثيات لمنطقة ما بالدخول لموقع <a rel="external nofollow" href="http://www.latlong.net/">LatLong</a> وكتابة اسم المدينة أو المنطقة.</p><p>في هذا المثال ستعرض الخريطة موقع تركيا Turkey.</p><p>لنقم الآن ضمن الدالة <span style="font-family:courier new,courier,monospace;">{} ()function initialize</span>، بتحديد خصائص الـخريطة ضمن الـمتغير <span style="font-family:courier new,courier,monospace;">mapProp</span>، مثل: الموقع الذي سيظهر عند تحميلها، نوعها، وحجم الـتكبير الذي نريده <span style="font-family:courier new,courier,monospace;">zoom</span>.</p><p>كما هو موضح في الـكود الـتالـي:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">&lt;script type="text/javascript"&gt; 
function initialize() { 
    var mapProp = { 
        center: new google.maps.LatLng(38.963745, 35.243322), 
        zoom: 5, 
        mapTypeId: google.maps.MapTypeId.ROADMAP 
    };
}
&lt;/script&gt;
</pre></div><div id="wmd-preview-section-53"><ul><li>نستخدم الخاصية <span style="font-family:courier new,courier,monospace;">zoom</span> لتحديد البعد الذي نريده للمكان (قريب – بعيد).</li><li>الخاصية <span style="font-family:courier new,courier,monospace;">mapTypeId</span> تحدد نوع الخريطة الذي سيظهر:<ul><li><strong>ROADMAP</strong> ( الخريطة العادية 2D map)</li><li><strong>SATELLITE</strong> (خريطة مصورة)</li><li><strong>HYBRID</strong> (خريطة مصورة بالإضافة الى أسماء الطرق والمدن)</li><li><strong>TERRAIN</strong> (خريطة تتضمن الجبال والأنهار…الـخ)</li></ul></li></ul><p>لنقم الآن بتعريف متغير <span style="font-family:courier new,courier,monospace;">map</span> وإعطاءه id الخاصة بالـ div:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">var map = new google.maps.Map(document.getElementById("map"), mapProp);</pre><p>ثم إضافة الحدث<span style="font-family:courier new,courier,monospace;"> DOM listener</span> الذي يقوم بتنفيذ الدالة <span style="font-family:courier new,courier,monospace;">()initialize</span> عند تحميل صفحة الويب:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">google.maps.event.addDomListener(window, 'load', initialize);</pre><p>ليصبح الكود على هذا الشكل:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">&lt;script type="text/javascript"&gt; 
function initialize() { 
    var mapProp = { 
        center: new google.maps.LatLng(38.963745, 35.243322), 
        zoom: 5, 
        mapTypeId: google.maps.MapTypeId.ROADMAP 
    }; 
    var map = new google.maps.Map(document.getElementById("map"), mapProp);
} 

google.maps.event.addDomListener(window, 'load', initialize); 
&lt;/script&gt;</pre><p>ستظهر لك الخريطة بهذا الشكل:</p></div><div id="wmd-preview-section-56"><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/560cd6eda3865___1.png.ec38fad0c66103e93f3b434a9b5cb39a.png"><img data-fileid="5407" class="ipsImage ipsImage_thumbnailed" alt="560cd6ee7602e___1.thumb.png.fc5c30dcca43" src="https://academy.hsoub.com/uploads/monthly_2015_10/560cd6ee7602e___1.thumb.png.fc5c30dcca43fa2670482659b184f152.png"></a></p></div><div id="wmd-preview-section-57"><h2 id="وضع-محددات-markers">وضع محددات Markers</h2></div><div id="wmd-preview-section-58"><h3 id="1-إضافة-محدد-واحد">إضافة محدد واحد</h3><p>لنقم الآن بتحديد موقع معين ووضع محدد (marker).</p><p>أولًا قم بتعريف مصفوفة تحتوي على الإحداثيات (خط الـطول وخط الـعرض) للمدينة أو البلد أو الموقع المعين الذي تريد تحديده. مثلًا مدينة اسطنبول Istanbul:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">var myLatLng = {lat: 41.008238, lng: 28.978359 };</pre><p>هنا سأقوم بإضافة محدد واحد ثم سأشرح كيف يمكننا إضافة أكثر من محدد.</p></div><div id="wmd-preview-section-59"><p>الآن نعطي للخاصية <span style="font-family:courier new,courier,monospace;">center</span> الـمتغير <span style="font-family:courier new,courier,monospace;">myLatLng:</span></p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">var map = new google.maps.Map(document.getElementById('map'), { zoom: 8, center: myLatLng });</pre><p>ثم نقوم بتعريف الـمحدد وإعطاء للخاصية <span style="font-family:courier new,courier,monospace;">position</span> الـمتغير <span style="font-family:courier new,courier,monospace;">myLatLng:</span></p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">var marker = new google.maps.Marker({ position: myLatLng, map: map, title: 'Hello World!' });</pre><p>سيظهر بهذا الشكل:</p></div><div id="wmd-preview-section-61"><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/560cd6fec789f___2.png.4512ec2f2760e74d61201a14dba2febe.png"><img data-fileid="5408" class="ipsImage ipsImage_thumbnailed" alt="560cd6ffbc538___2.thumb.png.04eed5a3671a" src="https://academy.hsoub.com/uploads/monthly_2015_10/560cd6ffbc538___2.thumb.png.04eed5a3671a2699d1ac6c9a17c6fed9.png"></a></p></div><div id="wmd-preview-section-62"><h3 id="2-إضافة-أكثر-من-محدد-على-نفس-الـخريطة">إضافة أكثر من محدد على نفس الـخريطة</h3><p>قم بتعريف مصفوفة تحتوي على إحداثيات المواقع الـتي تود تحديدها، سأقوم بتحديد 6 مدن: Istanbul, Antalya, Ankara, Trabzon, Bursa, Adana كما هو موضح أدناه:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">var myLocations = [ 
    ['Istanbul', 41.008238, 28.978359, 1], 
    ['Antalya', 36.896891, 30.713323, 2], 
    ['Ankara', 39.933363, 32.859742, 3], 
    ['Trabzon', 41.002697, 39.716763, 4], 
    ['Bursa', 40.188528, 29.060964, 5], 
    ['Adana', 36.991419, 35.330829, 6] 
];</pre><p>الآن عند تعريف المحدد قم بعمل <span style="font-family:courier new,courier,monospace;">for loop</span> حلقة تكرار وتعريف متغير <strong><span style="font-family:courier new,courier,monospace;">i</span></strong> ومن ثم إعطاء الـمصفوفة <span style="font-family:courier new,courier,monospace;">myLocations</span> للخاصية <span style="font-family:courier new,courier,monospace;">position:</span></p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">var marker, i; 
for (i = 0; i &lt; myLocations.length; i++) { 
    marker = new google.maps.Marker({ 
        position: new google.maps.LatLng(myLocations[i][1], myLocations[i][2]), 
        map: map 
    });
}</pre><p>وهذه هي المواقع التي قمنا بتحديدها:</p></div><div id="wmd-preview-section-64"><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/560cd70bdda43___3.png.1ac972688c52397ef3bf487a3a18bb12.png"><img data-fileid="5409" class="ipsImage ipsImage_thumbnailed" alt="560cd70cab70f___3.thumb.png.85d69cea1961" src="https://academy.hsoub.com/uploads/monthly_2015_10/560cd70cab70f___3.thumb.png.85d69cea19612a03b6b21bf1e6d3156f.png"></a></p></div><div id="wmd-preview-section-65"><h2 id="وضع-محدد-مع-لصيقة-label-عند-الـنقر-على-مكان-معين">وضع محدد مع لصيقة (label) عند الـنقر على مكان معين</h2><p>سأقوم هنا بشرح فكرة عن الـevents في Google map ثم سأتطرق فيما بعد لشرح الـevents بالتفصيل في مقال مقبل إن شاء الله.</p><p>الآن لنرى كيف يمكننا عند الضغط على مكان معين على الخريطة إظهار محدد مع لصيقة. مثال: marker A, marker B.</p><p>أولاً يجب تعريف متغير <span style="font-family:courier new,courier,monospace;">Labels</span> نضع فيه القيم الـتي نريد إظهارها في اللصيقة. مثال: الأحرف من A-Z.</p><p>ونحتاج أيضًا إلى تعريف متغير <span style="font-family:courier new,courier,monospace;">labelIndex</span> لتحديد الـقيمة الـتي نريد إظهارها.</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">var labels = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'; 
var labelIndex = 0;</pre><p>الآن قم بتحديد المكان الـذي ستفتح عنده الخريطة. مثال: تركيا.</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">var Turkey = { lat: 38.963745 , lng: 35.243322 }; 
var map = new google.maps.Map(document.getElementById('map'), { zoom: 12, center: Turkey });</pre><h3>الدالة ()addMarker</h3></div><div id="wmd-preview-section-67"><p>يقوم الحدث <span style="font-family:courier new,courier,monospace;">event.addListener</span> باستدعاء التابع<span style="font-family:courier new,courier,monospace;"> ()addMarker</span> عند الضغط على الخريطة. كما في المثال التالي:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">google.maps.event.addListener(map, ‘click’, function(event) {
    addMarker(event.latLng, map);
});</pre><p><span style="line-height: 1.6;">وليكون هناك marker محدد عند فتح الخريطة قم بإضافة محدد إلى Turkey:</span></p></div><div id="wmd-preview-section-68"><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">addMarker(Turkey, map);</pre><p><span style="line-height: 1.6;">لنكتب الآن الدالة </span><span style="line-height: 1.6; font-family: 'courier new', courier, monospace;">()addMarker:</span></p><p><span style="line-height: 1.6;">نحتاج لتعريف 2 </span>parameters<span style="line-height: 1.6;"> (معاملين) هما الـخريطة والـموقع <span style="font-family:courier new,courier,monospace;">map</span> &amp; <span style="font-family:courier new,courier,monospace;">location</span> ثم نقوم بتعريف <span style="font-family:courier new,courier,monospace;">marker</span> وإعطاء المعامل <span style="font-family:courier new,courier,monospace;">location</span> للخاصية <span style="font-family:courier new,courier,monospace;">position</span>. </span></p><p><span style="line-height: 1.6;">ولإظهار </span>label<span style="line-height: 1.6;"> نقوم بإعطاء الـمتغير <span style="font-family:courier new,courier,monospace;">labels</span> الـذي يحتوي على الأحرف من A-Z للخاصية <span style="font-family:courier new,courier,monospace;">label</span> مع تحديد<span style="font-family:courier new,courier,monospace;"> ++index</span> لكي ينتقل عند كل نقرة جديدة لحرف جديد وإظهاره على الـ marker كما هو موضح في الكود الـتالي:</span></p></div><div id="wmd-preview-section-69"><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">function addMarker(location, map) {

    var marker = new google.maps.Marker({
        position: location, 
        label: labels[labelIndex++ % labels.length], 
        map: map
    });
}</pre><p><span style="line-height: 1.6;">ستظهر لك الخريطة بهذا الشكل:</span></p><p style="text-align: center;"><span style="line-height: 1.6;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/560cd7869b9f0___4.png.be0c18afc71eb4102aba9e96fc4ad826.png"><img data-fileid="5410" class="ipsImage ipsImage_thumbnailed" alt="560cd7876a05f___4.thumb.png.7658d88d73d6" src="https://academy.hsoub.com/uploads/monthly_2015_10/560cd7876a05f___4.thumb.png.7658d88d73d6895ff929b028af2b302d.png"></a></span></p><p><span style="line-height: 1.6;">وعند النقر على الخريطة:</span></p><p style="text-align: center;"><span style="line-height: 1.6;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/560cd7c775249___5.png.bc3dbb4db31f9e637bf928bea2dd2f44.png"><img data-fileid="5411" class="ipsImage ipsImage_thumbnailed" alt="560cd7c8285ed___5.thumb.png.4939be204e42" src="https://academy.hsoub.com/uploads/monthly_2015_10/560cd7c8285ed___5.thumb.png.4939be204e42dc34198ac4c5448c8f55.png"></a></span></p><h3><span style="line-height: 1.6;">إضافة تأثير Marker Animation</span></h3><p><span style="line-height: 1.6;">يمكنك إضافة تأثير حركي على المحدد ليبدو وكأنه يقفز ، فقط باستخدام خاصية <span style="font-family:courier new,courier,monospace;">animation:google.maps.Animation.BOUNCE </span>كما هو موضح في الكود الـتالـي:</span></p></div><div id="wmd-preview-section-70"><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">var marker = new google.maps.Marker({
    position: myCenter,
    animation: google.maps.Animation.BOUNCE
});</pre><h3><span style="line-height: 1.6;">إضافة أيقونة للمحدد </span></h3><p><span style="line-height: 1.6;">يمكنك تغيير الأيقونة الخاصة بالمحدد ووضع أيقونة من اختيارك عن طريق الخاصية <span style="font-family:courier new,courier,monospace;">icon</span>، حيث تقوم بإعطاء مسار الصورة للخاصية <strong><span style="font-family:courier new,courier,monospace;">icon.</span></strong> كما هو موضح في الكود التالي:</span></p></div><div id="wmd-preview-section-71"><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">var marker = new google.maps.Marker({
    position: myCenter,
    icon:'pin.png'
});</pre><p><span style="line-height: 1.6;">ستظهر لك الخريطة بهذا الشكل:</span></p><p style="text-align: center;"><span style="line-height: 1.6;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/560cd7d370772___6.png.b3b4e7fd4f47997106fe6cad9d95871e.png"><img data-fileid="5412" class="ipsImage ipsImage_thumbnailed" alt="560cd7d421b99___6.thumb.png.6eb37a3932dc" src="https://academy.hsoub.com/uploads/monthly_2015_10/560cd7d421b99___6.thumb.png.6eb37a3932dc3ec2e9d0e59278b18f03.png"></a></span></p><h2><span style="line-height: 1.6;">إضافة شكل متعدد الخطوط Polyline </span></h2><p><span style="line-height: 1.6;">تتيح لك ميزة <strong>polyline</strong> رسم خط يصل بين سلسلة إحداثيات على الخريطة بشكل متسلسل، على سبيل المثال يمكنك رسم مسار رحلة عبر مجموعة من المدن ويمكنك التحكم بخصائص عديدة للخط مثل اللون والشفافية والحجم. </span></p><p><strong><span style="line-height: 1.6;">خصائص الميزة </span><span style="line-height: 22.4px;">Polyline:</span></strong></p><ul><li><span style="line-height: 1.6;"><strong>path</strong> - تحدد مجموعة الإحداثيات التي سيمر بها الخط.</span></li><li><span style="line-height: 1.6;"><strong>strokeColor</strong> - يحدد لون الخط بالـHex كود.</span></li><li><span style="line-height: 1.6;"><strong>strokeOpacity</strong> - يحدد شفافية الخط بين 0.0 و 1.0.</span></li><li><span style="line-height: 1.6;"><strong>strokeWeight</strong> - يحدد عرض الخط بالبكسل.</span></li><li><span style="line-height: 1.6;"><strong>Editable</strong> - تحدد ما إذا كان الخط قابل للتعديل من قبل المستخدم أم لا. </span></li></ul><p><span style="line-height: 1.6;">لنقم الآن بتحديد مجموعة إحداثيات لمدن ونصل فيما بينها عن طريق polyline، سأستخدم نفس الإحداثيات التي استخدمتها في تحديد المدن عندما وضعت أكثر من محدد، سأقوم برسم خط بين ثلاث مدن: اسطنبول، انطالـيا، طرابزون. </span></p><p><strong><span style="line-height: 1.6;">أولاً: تحديد إحداثيات الـمدن:</span></strong></p></div><div id="wmd-preview-section-72"><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">var istanbul = new google.maps.LatLng(41.008238, 28.978359);

var antalya = new google.maps.LatLng(36.896891, 30.713323);

var trabzon = new google.maps.LatLng(41.002697, 39.716763);</pre><p><span style="line-height: 1.6;"><strong>ثانيًا: نقوم بتعريف مصفوفة myTrip وتعبئتها بأسماء المتغيرات</strong> (المدن الـتي نريد تحديد المسار عليها ):</span></p></div><div id="wmd-preview-section-73"><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">var myTrip = [ istanbul, antalya, trabzon];</pre><p>وثم نعطي المصفوفة للخاصية <span style="font-family:courier new,courier,monospace;">path</span>:</p></div><div id="wmd-preview-section-74"><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">path: myTrip,</pre><p><span style="line-height: 1.6;"><strong>ثالثًا: نقوم بتعريف متغير flightPath لاختيار الـخاصية polyline:</strong></span></p><p><span style="line-height: 1.6;">كما هو موضح في الكود الـتالي:</span></p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">var map = new google.maps.Map(document.getElementById(“map”),mapProp);
var myTrip = [ istanbul, antalya, trabzon];
var flightPath = new google.maps.Polyline({
    path:myTrip,
    strokeColor: "#0000FF",
    strokeOpacity: 0.8,
    strokeWeight: 2
});

flightPath.setMap(map);
}</pre><p><span style="line-height: 1.6;">ستظهر لك الخريطة بهذا الشكل:</span></p><p style="text-align: center;"><span style="line-height: 1.6;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/560cd7e2de702___7.png.c95fae6b0316fb5c1254e0a1899ae422.png"><img data-fileid="5413" class="ipsImage ipsImage_thumbnailed" alt="560cd7e39ca7d___7.thumb.png.444cc649e81c" src="https://academy.hsoub.com/uploads/monthly_2015_10/560cd7e39ca7d___7.thumb.png.444cc649e81c488bc122fc115154e71e.png"></a></span></p><h2><span style="line-height: 1.6;">إضافة مضلع Polygon</span></h2><p><span style="line-height: 1.6;">تتيح لك هذه الـميزة إنشاء مضلع تكون زواياه عبارة عن سلسلة الإحداثيات التي تريد الوصل بينها. لا تختلف ميزة <strong>polygon</strong> كثيراً عن polyline من حيث كتابة الـتعليمات فقط نقم باستبدالـ polyline بـpolygon.</span></p><p><strong><span style="line-height: 1.6;">خصائص الـميزة </span><span style="line-height: 22.4px;">polygon:</span></strong></p><ul><li><span style="line-height: 1.6;"><strong>path</strong> - تحدد مجموعة الإحداثيات التي سيمر بها الخط.</span></li><li><span style="line-height: 1.6;"><strong>strokeColor</strong> - يحدد لون الخط بالـHex كود.</span></li><li><span style="line-height: 1.6;"><strong>strokeOpacity</strong> - يحدد شفافية الخط بين 0.0 و 1.0.</span></li><li><span style="line-height: 1.6;"><strong>strokeWeight</strong> - يحدد عرض الخط بالبكسل.</span></li><li><span style="line-height: 1.6;"><strong>fillColor</strong> - يحدد لون المضلع بالـHex كود.</span></li><li><span style="line-height: 1.6;"><strong>fillOpacity</strong> - يحدد نسبة الشفافية للمضلع بين 0.0 و 1.0.</span></li><li><span style="line-height: 1.6;"><strong>Editable</strong> - تحدد ما إذا كان الخط قابل للتعديل من قبل المستخدم أم لا. </span></li></ul><p><span style="line-height: 1.6;">كما هو موضح في الكود التالي:</span></p></div><div id="wmd-preview-section-76"><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">var map = new google.maps.Map(document.getElementById(“map”),mapProp);
var myTrip = [istanbul, antalya, trabzon];
var flightPath = new google.maps.Polygon({
    path: myTrip,
    strokeColor: "#0000FF",
    strokeOpacity: 0.8,
    strokeWeight: 2
});

flightPath.setMap(map);
}</pre><p>ستظهر لك الـخريطة بهذا الـشكل:</p></div><div id="wmd-preview-section-77"><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/560cd7eecdb9d___8.png.a2cb3295985180cec339a84fd1a4d1f3.png"><img data-fileid="5414" class="ipsImage ipsImage_thumbnailed" alt="560cd7ef9c6f6___8.thumb.png.d924939b89d7" src="https://academy.hsoub.com/uploads/monthly_2015_10/560cd7ef9c6f6___8.thumb.png.d924939b89d7addc4bd11318f36b83d6.png"></a></p><h2>إضافة دائرة Circle</h2><p>تتيح لك هذه الميزة إحاطة منطقة معينة على الخريطة بدائرة، يمكنك التحكم بقطر الدائرة ولونها وشفافيتها.</p><p><strong>خصائص الميزة Circle:</strong></p><ul><li><strong>center</strong> - تحديد إحداثيات مركز الدائرة. </li><li><strong>radius</strong> - تحديد قطر الدائرة بالمتر المربع. </li><li><strong>strokeColor</strong> - يحدد لون الخط بالـHex كود.</li><li><strong>strokeOpacity</strong> - يحدد شفافية الخط بين 0.0 و 1.0.</li><li><strong>strokeWeight</strong> - يحدد عرض الخط بالبكسل.</li><li><strong>fillColor </strong>- يحدد لون المضلع بالـHex كود.</li><li><strong>fillOpacity</strong> - يحدد نسبة الشفافية للمضلع بين 0.0 و 1.0.</li><li><strong>Editable</strong> - تحدد ما إذا كان الخط قابل للتعديل من قبل المستخدم أم لا.</li></ul><p>كما هو موضح في الكود التالي:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">var map = new google.maps.Map(document.getElementById(“map”), mapProp);

var flightPath = new google.maps.Circle({
    center: istanbul, 
    radius: 20000, 
    strokeColor: "#0000FF", 
    strokeOpacity: 0.8, 
    strokeWeight: 2, 
    fillColor: "#0000FF", 
    fillOpacity: 0.4 
}); 

flightPath.setMap(map);
</pre></div><div id="wmd-preview-section-78"><p>ستظهر لك الخريطة بهذا الشكل:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/560cd80782ab6___9.png.1c46ac69668eb508eb4e2d6816efd2ca.png"><img data-fileid="5415" class="ipsImage ipsImage_thumbnailed" alt="560cd80820082___9.thumb.png.b0b8b7cd5e53" src="https://academy.hsoub.com/uploads/monthly_2015_10/560cd80820082___9.thumb.png.b0b8b7cd5e5387c98f68f41c09af459e.png"></a></p><h2>إضافة نافذة نصية InfoWindow</h2><p>تتيح لك ميزة <strong>infoWindow</strong> إظهار نافذة على موقع معين محدد باسم بحيث يمكنك كتابة اسم الموقع المحدد بداخلها. كما هو موضح في الكود التالي:</p><pre data-pbcklang="javascript" data-pbcktabsize="4" class="javascript ipsCode prettyprint">var map = new google.maps.Map(document.getElementById(“map”), mapProp);

var marker = new google.maps.Marker({
    position: new google.maps.LatLng(38.963745, 35.243322),
});

marker.setMap(map);

var infowindow = new google.maps.InfoWindow({
    content:”Hello World!”
});

infowindow.open(map, marker);
}</pre><p>ستظهر لك الخريطة بهذا الشكل:</p><p style="text-align: center;"><a class="ipsAttachLink ipsAttachLink_image" href="https://academy.hsoub.com/uploads/monthly_2015_10/560cd83a1eb72___10.png.6f90c60c646be4293c6bf5987790bb01.png"><img data-fileid="5416" class="ipsImage ipsImage_thumbnailed" alt="560cd83ad6ce6___10.thumb.png.7cd7831ff00" src="https://academy.hsoub.com/uploads/monthly_2015_10/560cd83ad6ce6___10.thumb.png.7cd7831ff003c74dd0ec7dddec20dca2.png"></a></p><p>هكذا نكون قد استعرضنا أهم النقاط والميزات التي تتيح لك استخدام خرائط Google Maps بسهولة في موقعك الخاص.</p><p>هل أنت جاهز الآن لإضافة Google Maps إلى موقعك والإستفادة من مزاياها؟</p></div><div id="wmd-preview-section-79"><h5 id="الـمصادر">الـمصدر: <a rel="external nofollow" href="https://developers.google.com/maps/web/">Google Developers</a>.</h5><p>حقوق الصورة البارزة: <a rel="external nofollow" href="http://www.freepik.com/free-vector/vectors_714013.htm">Designed by Freepik</a>.</p></div></div>
]]></description><guid isPermaLink="false">181</guid><pubDate>Thu, 01 Oct 2015 19:56:22 +0000</pubDate></item><item><title>&#x645;&#x62F;&#x62E;&#x644; &#x625;&#x644;&#x649; &#x62C;&#x627;&#x641;&#x627;&#x633;&#x643;&#x631;&#x64A;&#x628;&#x62A; &#x643;&#x627;&#x626;&#x646;&#x64A;&#x629; &#x627;&#x644;&#x62A;&#x648;&#x62C;&#x647; (Object-Oriented JavaScript)</title><link>https://academy.hsoub.com/programming/javascript/%D9%85%D8%AF%D8%AE%D9%84-%D8%A5%D9%84%D9%89-%D8%AC%D8%A7%D9%81%D8%A7%D8%B3%D9%83%D8%B1%D9%8A%D8%A8%D8%AA-%D9%83%D8%A7%D8%A6%D9%86%D9%8A%D8%A9-%D8%A7%D9%84%D8%AA%D9%88%D8%AC%D9%87-object-oriented-javascript-r179/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2018_01/7.png.f3b324c5e299fb203817e8e4911a0133.png" /></p>

<p>
	﻿هل تعاني من صعوبة في تطبيق مفاهيم البرمجة الكائنية مع لغة JavaScript؟ إذًا أنت في المكان الصحيح، ففي هذا المقال سنبدأ بمطلع لمفاهيم البرمجة الكائنية (أو الشيئية كما قد يُطلق عليها البعض)، ومن ثم مراجعة نموذج جافا سكريبت في الكائنات، وأخيرًا شرح مفاهيم البرمجة الكائنية في جافا سكريبت، لتحصل على إلمام واف والقصة الكاملة.
</p>

<p style="text-align: center;">
	<img alt="7.png" class="ipsImage ipsImage_thumbnailed" data-fileid="26672" data-unique="iwf8vt68x" src="https://academy.hsoub.com/uploads/monthly_2018_01/7.png.eac7c298a4a0dd5bb0ee6eed37894431.png"></p>

<h2>
	مراجعة في جافاسكريبت JavaScript
</h2>

<p>
	يُمكن العودة إلى المقال <a href="https://academy.hsoub.com/programming/javascript/%D8%A5%D8%B9%D8%A7%D8%AF%D8%A9-%D8%AA%D9%82%D8%AF%D9%8A%D9%85-javascript-%D9%84%D9%85%D9%86-%D8%A3%D8%B3%D8%A7%D8%A1-%D9%81%D9%87%D9%85%D9%87%D8%A7-r92/" rel="">إعادة تقديم JavaScript لمن أساء فهمها</a> هنا في أكاديمية حسوب للحصول على مراجعة لأساسيات لغة جافا سكريبت وأخذ فكرة عن المغيرات وأنواع الدوال وبقية الأساسيات.
</p>

<h2>
	البرمجة الكائنية Object-oriented programming
</h2>

<p>
	إن البرمجة الكائنية (<abbr title="Object-Oriented Programming | البرمجة كائنية التوجه">OOP</abbr>) ما هي إلا نمط برمجي يَستخدم التجريد في إنشاء نماذج/نسخ لتجسيد العالم الحقيقي، وتَستخدم البرمجة الكائنية في ذلك أساليب مُتعدّدة من هذا النمط، فهي تستخدم الوحدات module، وتعدديّة الأشكال polymorphism والتغليف encapsulation، وتجدر الإشارة إلى أن معظم لغات البرمجة تدعم مفهوم <abbr title="Object-Oriented Programming | البرمجة كائنية التوجه">OOP</abbr> أمثال اللغات البرمجية: جافا، بايثون، روبي، وطبعًا جافا سكريبت.
</p>

<p>
	يُعالج أو لنقل يَتصور مفهوم البرمجة الكائنية <abbr title="Object-Oriented Programming | البرمجة كائنية التوجه">OOP</abbr> البرنامج كتشكيلة من الأشياء/الكائنات المتعاونة/المترابطة بدلًا من يتصوّره كتشكيلة من الدوال (functions) أو كسرد من الأوامر. ففي مفهوم <abbr title="Object-Oriented Programming | البرمجة كائنية التوجه">OOP</abbr>، كل كائن/شيء له القدرة على استقبال الرسائل، ومعالجة البيانات، وإرسال الرسائل إلى باقي الكائنات، ويُمكن اعتبار أنه لكل كائن object كينونة خاصة به ودور/وظيفة مستقلة عن الكائن الآخر.
</p>

<p>
	تُعزز البرمجة الكائنية القدرة على صيانة الشيفرة البرمجية والمرونة في التطوير، وأثبتت جدارتها على نطاق واسع في هندسة البرمجيات الكبيرة، ولأن البرمجة الكائنية تُشدد على استخدام الوحدات module، فإن الشيفرة/الكود المكتوب بمفهوم البرمجة الكائنية هو أبسط في التطوير وأسهل في الفهم مستقبلًا (عند التنقيح والتعديل)، وكما يعزز مفهوم البرمجة الكائنية التحليل المباشر للشيفرة، وفهم الحالات الشائكة فهمًا أفضل من باقي الأساليب البرمجية الأخرى.
</p>

<h2>
	مصطلحات البرمجة الكائنية
</h2>

<h3>
	المجال في البرمجة الكائنية Namespace
</h3>

<p>
	ما هو إلا عبارة عن حاوي تسمح للمطوّر بتحزيم جميع الوظائف تحت اسم محدد وفريد.
</p>

<h3>
	الصنف أو الفئة Class في البرمجة الكائنية
</h3>

<p>
	يعتني الصنف بكل ما يتعلّق بميزات وخصائص الكائن، والصنف ما هو إلا قالب template تعريفي بخاصيات properties وبطُرق/وظائف methods الكائن object.
</p>

<h3>
	الكائن Object في البرمجة الكائنية
</h3>

<p>
	الكائن ما هو إلا حالة/أمثولة instance من صنف class.
</p>

<h3>
	الخاصية property في البرمجة الكائنية
</h3>

<p>
	ما هي إلا مميزات وخصائص الكائن، كاللون مثلًا.
</p>

<h3>
	الطريقة أو الوظيفة Method في البرمجة الكائنية
</h3>

<p>
	تعتني الطريقة أو الوظيفة كما يُسميها البعض بقدرات الكائن، مثل قدرة المشي مثلًا، وهي دور أو وظيفة مرتبطة مع صنف class.
</p>

<h3>
	المشيد Constructor في البرمجة الكائنية
</h3>

<p>
	ما هو إلا طريقة method تُستدعى في لحظة استهلال instantiate الكائن، وعادةً ما يكون له نفس اسم الصنف الذي يحتويه.
</p>

<h3>
	الوراثة Inheritance في البرمجة الكائنية
</h3>

<p>
	يُمكن للصنف أن يرث مميزات من صنف آخر.
</p>

<h3>
	التغليف Encapsulation في البرمجة الكائنية
</h3>

<p>
	طريقة في تحزيم البيانات data والطُرق methods التي تستخدم البيانات.
</p>

<h3>
	التجريد Abstraction في البرمجة الكائنية
</h3>

<p>
	يجب على الاقتران الحاصل من: الوراثة والطُرق methods والخاصيات properties لكائن معقد وشائك التمثيل برمجيًا أن يعكس الواقع المراد محاكاته في البرمجة الكائنية.
</p>

<h3>
	تعددية الأشكال Polymorphism في البرمجة الكائنية
</h3>

<p>
	تحمل كلمة Poly بحد ذاتها المعنى "متعدد" وتحمل الكلمة morphism المعنى "أشكال، ويُشير المفهوم ككل إلى أن أكثر من صنف قد يُعرّف نفس الطريقة method أو الخاصية property.
</p>

<h2>
	البرمجة المعتمدة على النموذج الأولي Prototype
</h2>

<p>
	البرمجة المعتمدة على النموذج الأوّلي (Prototype-based programming) ما هي إلا نموذج من البرمجة الكائنية <abbr title="Object-Oriented Programming | البرمجة كائنية التوجه">OOP</abbr> ولكنها لا تستخدم الأصناف classes، بل تقوم أولًا بإعداد سلوك أي صنف class ما ومن ثم تُعيد استخدامه، ويُطلق البعض على هذا النموذج: البرمجة بلا أصناف classless، أو البرمجة المَبْدَئِية المنحى prototype-oriented، أو البرمجة المعتمدة على الأمثولة instance-based).
</p>

<p>
	يعود أصل اللغة المعتمدة على النموذج الأولي إلى لغة <a href="http://en.wikipedia.org/wiki/Self%20(programming%20language" rel="external nofollow">Self</a>، والتي طوّرها David Ungar وRandall Smith، ولكن أسلوب البرمجة بدون أصناف class-less توسّع ونال شهرة كبيرة في العقد الأخير، واُعتمد من قبل العديد من اللغات البرمجية أشهرهم جافا سكريبت.
</p>

<h2>
	البرمجة الكائنية باستخدام جافا سكريبت
</h2>

<h3>
	المجال Namespace في جافا سكريبت
</h3>

<p>
	المجال هو أشبه بمستوعب/بحاوية (container) تسمح للمطوّر في تحزيم وظائف تحت اسم فريد، أو اسم تطبيق محدد، ففي جافا سكريبت المجال هو مجرد كائن object كأي كائن آخر يحتوي على طُرق methods، وخاصيات properties، وحتى كائنات objects.
</p>

<p>
	<strong>ملاحظة هامة</strong>: من المهم جدًا الانتباه إلى أنه في جافا سكريبت، لا يوجد فرق بين الكائنات العادية والمجالات namespaces، وهذا يختلف عن اللغات الكائنية الأخرى، الأمر الذي قد يُربك المبرمجين المبتدئين في جافا سكريبت.
</p>

<p>
	إن إنشاء مجال namespace في جافا سكريبت بسيطٌ للغاية، فمن خلال إنشاء كائن عام/مشترك/شامل global، ستصبح جميع المُتغيّرات variables والطرق methods، والدوال functions خاصياتٍ لهذا الكائن، ويٌقلل استخدام المجالات namespaces أيضًا من احتمالية تضارب الأسماء في التطبيق، منذ أن كل كائن من كائنات التطبيق ما هي إلى خاصيات كائن شامل/عام معرّفة على مستوى التطبيق.
</p>

<p>
	سيُنشئ في الخطوة التالية كائنًا عامًا global وبالاسم <code>MYAPP</code>:
</p>

<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
// global namespace 
var MYAPP = MYAPP || {};</pre>

<p>
	يُظهر المثال السابق، كيف تم التأكّد أولًا فيما إذا كان <code>MYAPP</code> معرفًا (سواء في نفس الملف أو في آخر)، ففي حال الإيجاب سيُستخدم الكائن العام <code>MYAPP</code>، وفي حال عدم تعريفه مُسبقًا سيُنشئ كائنًا خالٍ وبالاسم <code>MYAPP</code> والذي سيغلّف encapsulate الطرق methods والدوال functions والمتغيرات variables والكائنات objects.
</p>

<p>
	كما يُمكن أيضًا إنشاء مجال فرعي sub-namespaces:
</p>

<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
// sub namespace 
MYAPP.event = {};</pre>

<p>
	يوضّح المثال التالي الصيغة المستخدمة في إنشاء مجال namespace وإضافة متغيرات ودوال:
</p>

<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
// Create container called MYAPP.commonMethod for common method and properties
MYAPP.commonMethod = {
  regExForName: "", // define regex for name validation
  regExForPhone: "", // define regex for phone no validation
  validateName: function(name){
    // Do something with name, you can access regExForName variable
    // using "this.regExForName"
  },
 
  validatePhoneNo: function(phoneNo){
    // do something with phone number
  }
}

// Object together with the method declarations
MYAPP.event = {
    addListener: function(el, type, fn) {
    // code stuff
    },
    removeListener: function(el, type, fn) {
    // code stuff
    },
    getEvent: function(e) {
    // code stuff
    }
  
    // Can add another method and properties
}

// Syntax for Using addListener method:
MYAPP.event.addListener("yourel", "type", callback);</pre>

<h3>
	الكائنات الأساسية/القياسية المبنية داخل لغة جافا سكريبت Standard built-in objects
</h3>

<p>
	تتضمن لغة جافا سكريبت العديد من الكائنات في تركيبتها، على سبيل المثال، يوجد كائنات مثل <code>Math</code>، <code>Object</code>، <code>Array</code>، <code>String</code>، ويُظهر المثال التالي كيفيّة استخدام الكائن <code>Math</code> للحصول على رقم عشوائي باستخدام أحد طُرق method هذا الكائن وهي الطريقة <span style="font-family:courier new,courier,monospace;">()</span><code>random</code>.
</p>

<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
console.log(Math.random());</pre>

<p>
	<strong>ملاحظة</strong>: يَفترض المثال السابق وجميع الأمثلة التالية في المقال وجود دالة function بالاسم <span style="font-family:courier new,courier,monospace;">()</span><code>console.log</code> معرّفة تعريفًا عامًا (globally)، مع العلم أن هذه الدالة ليست جزء من اللغة نفسها، ولكنها دالة متوفّرة في العديد من متصفحات الإنترنت لأغراض تشخيص الشيفرة البرمجية debugging.
</p>

<p>
	يُمكن العودة إلى <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects" rel="external nofollow">مرجع لغة جافا سكريبت: الكائنات الأصلية المعيارية</a> للحصول على قائمة بالكائنات المبينة داخل لغة جافا سكريبت نفسها.
</p>

<p>
	كل كائن في جافا سكريبت هو حالة/أمثولة instance من الكائن <code>Object</code> ويَرث كافة خاصياته properties وطُرقه methods.
</p>

<h3>
	الكائنات المخصصة Custom objects في جافا سكريبت
</h3>

<h4>
	الصنف/الفئة The class
</h4>

<p>
	لغة جافا سكريبت لغة من النوع prototype-based ولا تحتوي على العبارة <code>class</code> كما هو حال باقي لغات البرمجة الكائنية، كما في روبي أو بايثون، ويُربك هذا الأمر المبرمجين المعتادين على اللغات التي تعتمد على هذه العبارة أو المفهوم، وتستخدم جافا سكريبت بدلًا من ذلك الدوال functions لمحاكات مفهوم الأصناف classes، وتعريف صنف هو بسهولة تعريف أي دالّة:
</p>

<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
var Person = function () {};</pre>

<h4>
	الكائن (أمثولة الصنف class instance)
</h4>

<p>
	يتطلب إنشاء حالة/أمثولة instance جديدة من كائن <code>obj</code> استخدام العبارة <code>new obj</code>، وتعيين النتيجة إلى متغيّر بغرض الوصول إلى فيما بعد.
</p>

<p>
	عُرّف في الشيفرة السابقة صنف class بالاسم <code>Person</code>، وفي الشيفرة التالية، سيُنشئ حالتين/أمثولتين instances من هذا الصنف، الأولى بالاسم <code>person1</code> والثانية بالاسم <code>person2</code>.
</p>

<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
var person1 = new Person(); 
var person2 = new Person();</pre>

<h4>
	المشيد The constructor
</h4>

<p>
	يُستدعى المُشيّد constructor في لحظة الاستهلال instantiation (اللحظة التي يُنشئ فيها الكائن)، والمُشيّد ما هو إلا طريقة method من طُرق الصنف class، وفي جافا سكريبت تعمل الدالة على تشييد الكائن، ولذلك لا داعي إلى تعريف طريقة method من أجل عميلة التشييد، وكل إجراء مصرّح في الصنف class يُنفّذ في لحظة الاستهلال instantiation.
</p>

<p>
	يُستخدم المُشيّد في تعيين خاصيات properties الكائن، أو في استدعاء طُرق methods معينة لتحضير الكائن للاستخدام، وأما إضافة طُرق صنف وتعريفها يحدث باستخدام صيغة syntax مختلفة سنتطرّق إليها فيما بعد خلال المقال.
</p>

<p>
	تُظهر الشيفرة التالية كيف يُسجّل log (يُرسل رسالة نصية إلى طرفية المتصفح console) مُشيّد الصنف <code>Person</code> رسالة نصية حينما يُستهل instantiated.
</p>

<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
var Person = function () {
  console.log('instance created');
};

var person1 = new Person();
var person2 = new Person();</pre>

<h4>
	الخاصية The property (خاصية الكائن object attribute)
</h4>

<p>
	الخاصيات properties ما هي إلا متغيرات محتوات في الصنف class، وكل حالة/أمثولة من الكائن تمتلك هذه الخاصيات، وتُعيّن الخاصيات في دالة مُشيّد الصنف بحيثُ تُنشئ مع كل حالة/أمثولة instance.
</p>

<p>
	إن الكلمة المفتاحية <code>this</code>، والتي تُشير إلى الكائن الحالي، تسمح للمطوّر بالعمل مع الخاصيات من ضمن الصنف، والوصول (قراءةً وكتابةً) إلى الخاصية property من خارج الصنف يكون من خلال الصيغة <code>InstanceName.Property</code> كما هو الأمر في لغة C++ (سي بلس بلس) وJava والعديد من اللغات الأخرى، ومن داخل الصنف تُستخدم الصيغة <code>this.Property</code> للحصول على قيمة الخاصية أو لتعيين قيمتها.
</p>

<p>
	في الشيفرة التالية، عُرّفت الخاصية <code>firstName</code> للصنف <code>Person</code> وفي لحظة الاستهلال instantiation:
</p>

<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
var Person = function (firstName) {
  this.firstName = firstName;
  console.log('Person instantiated');
};

var person1 = new Person('Alice');
var person2 = new Person('Bob');

// Show the firstName properties of the objects
console.log('person1 is ' + person1.firstName); // logs "person1 is Alice"
console.log('person2 is ' + person2.firstName); // logs "person2 is Bob"</pre>

<h4>
	الطرق The methods
</h4>

<p>
	الطرق methods ما هي إلا دوال (وتُعرّف كما تعرّف الدوال functions)، فيما عدا ذلك فهي تُشبه الخاصيات properties، واستدعاء طريقة method مشابه إلى الوصول إلى خاصيّة ما، ولكن مع إضافة <code>()</code> في نهاية اسم الطريقة، وربما مع مُعطيات arguments، ولتعريف طريقة، تُعيّن دالة إلى خاصيّة مُسمّات من خاصيّة الصنف <code>prototype</code>، ويُمكن فيما بعد استدعاء الطريقة على الكائن بنفس الاسم الذي عُيّن للدالة.
</p>

<p>
	في الشيفرة التالية، عُرّفت ومن ثم اُستخدِمت الطريقة <span style="font-family:courier new,courier,monospace;">()</span><code>sayHello</code> للصنف <code>Person</code>.
</p>

<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
var Person = function (firstName) {
  this.firstName = firstName;
};

Person.prototype.sayHello = function() {
  console.log("Hello, I'm " + this.firstName);
};

var person1 = new Person("Alice");
var person2 = new Person("Bob");

// call the Person sayHello method.
person1.sayHello(); // logs "Hello, I'm Alice"
person2.sayHello(); // logs "Hello, I'm Bob"</pre>

<p>
	إن الطُرق methods في جافا سكريبت ما هي إلا دالة كائن عادية مرتبطة مع كائن كخاصية property، وهذا يعني أنه يُمكن استدعاء الطُرق خارج السياق، كما في المثال التالي:
</p>

<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
var Person = function (firstName) {
  this.firstName = firstName;
};

Person.prototype.sayHello = function() {
  console.log("Hello, I'm " + this.firstName);
};

var person1 = new Person("Alice");
var person2 = new Person("Bob");
var helloFunction = person1.sayHello;

// logs "Hello, I'm Alice"
person1.sayHello();

// logs "Hello, I'm Bob"
person2.sayHello();

// logs "Hello, I'm undefined" (or fails
// with a TypeError in strict mode)
helloFunction();                                    

// logs true
console.log(helloFunction === person1.sayHello);

// logs true
console.log(helloFunction === Person.prototype.sayHello);

// logs "Hello, I'm Alice"
helloFunction.call(person1);</pre>

<p>
	كما يُظهر المثال السابق، جميع الإحالات المستخدمة في استدعاء الدالة <code>sayHello</code> تُشير إلى <strong><em>نفس الدالة</em></strong> سواءً الاستدعاء الحاصل مع <code>person1</code> أو <code>Person.prototype</code> أو حتى في المتغيّر <code>helloFunction</code> وقيمة <code>this</code> خلال استدعاء الدالة يعتمد على الكيفية التي تُستدعى فيها، حيث تُشير الكلمة المفتاحية <code>this</code> إلى الكائن الحالي الذي تُستدعى عليه الطريقة method، بمعنى عندما تم استدعاء الطريقة <span style="font-family:courier new,courier,monospace;">()</span><code>sayHello </code>على الكائن <code>person1</code> فإن <code>this</code> تُشير إلى الكائن <code>person1</code>، وعند استدعاء <code>sayHello</code> على الكائن <code>person2</code> فإن <code>this</code> تُشير إلى الكائن <code>person2</code>، ولكن إن تم الاستدعاء بطريقة مختلفة، فإن <code>this</code> ستُعيّن تعينًا مختلفًا، فاستدعاء <code>this</code> من المتغيّر (كما في <span style="font-family:courier new,courier,monospace;">()</span><code>helloFunction</code>) سيُعيّن <code>this</code> إلى الكائن العام global (والذي سيكون window في متصفح الإنترنت)، ومنذ أن هذا الكائن (على الأغلب) لا يملك الخاصّيّة <code>firstName</code>، ستكون النتيجة كما هو الحال في المثال السابق “Hello, I’m undefined”، كما يمكن دائمًا تعيين <code>this</code> صراحةً باستخدام <code>Function#call</code> (أو <code>Function#apply</code>) وهو كما كان في نهاية المثال.
</p>

<h4>
	الوراثة
</h4>

<p>
	تُستخدم الوراثة في جافا سكريبت في إنشاء صنف class كمثيل مخصص لصنف أو أكثر (<strong><em>تدعم جافا سكريبت وراثة وحيدة فقط single inheritance</em></strong>)، ويُطلق على الصنف المخصص عادةً <strong><em>ابن</em></strong> (child)، ويطلق على الصنف الآخر عادةً  <strong><em>الأب</em></strong> (parent)، وفي جافا سكريبت يتمّ ذلك من خلال إسناد حالة/أمثولة من الصنف الأب إلى الصنف الابن، ومن ثم تخصيصه، وفي متصفحات الإنترنت الحديثة يُمكن استخدام <code>Object.create</code> في تحقيق الوراثة inheritance أيضًا.
</p>

<p>
	<strong>ملاحظة</strong>: لا تتفقد جافا سكريبت مُشيّد صنف الابن <code>prototype.constructor</code> (راجع <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/prototype" rel="external nofollow"><code>Object.prototype</code></a>)، وعليه يجب التصريح عن ذلك يدويًا، لمزيد من التفصيل راجع السؤال التالي على <a href="http://stackoverflow.com/questions/8453887/why-is-it-necessary-to-set-the-prototype-constructor" rel="external nofollow">Stackoverflow</a>.
</p>

<p>
	عُرّف في الشيفرة التالية الصنف <code>Student</code> كصنف ابن للصنف <code>Person</code>، ومن ثم أُعيد تعريف الطريقة <span style="font-family:courier new,courier,monospace;">()</span><code>sayHello</code> وأُضيفت الطريقة <span style="font-family:courier new,courier,monospace;">()</span><code>sayGoodBye</code> علاوة على ذلك.
</p>

<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
// Define the Person constructor
var Person = function(firstName) {
  this.firstName = firstName;
};

// Add a couple of methods to Person.prototype
Person.prototype.walk = function(){
  console.log("I am walking!");
};

Person.prototype.sayHello = function(){
  console.log("Hello, I'm " + this.firstName);
};

// Define the Student constructor
function Student(firstName, subject) {
  // Call the parent constructor, making sure (using Function#call)
  // that "this" is set correctly during the call
  Person.call(this, firstName);

  // Initialize our Student-specific properties
  this.subject = subject;
};

// Create a Student.prototype object that inherits from Person.prototype.
// Note: A common error here is to use "new Person()" to create the
// Student.prototype. That's incorrect for several reasons, not least 
// that we don't have anything to give Person for the "firstName" 
// argument. The correct place to call Person is above, where we call 
// it from Student.
Student.prototype = Object.create(Person.prototype); // See note below

// Set the "constructor" property to refer to Student
Student.prototype.constructor = Student;

// Replace the "sayHello" method
Student.prototype.sayHello = function(){
  console.log("Hello, I'm " + this.firstName + ". I'm studying "
              + this.subject + ".");
};

// Add a "sayGoodBye" method
Student.prototype.sayGoodBye = function(){
  console.log("Goodbye!");
};

// Example usage:
var student1 = new Student("Janet", "Applied Physics");
student1.sayHello();   // "Hello, I'm Janet. I'm studying Applied Physics."
student1.walk();       // "I am walking!"
student1.sayGoodBye(); // "Goodbye!"

// Check that instanceof works correctly
console.log(student1 instanceof Person);  // true 
console.log(student1 instanceof Student); // true</pre>

<p>
	فيما يخص السطر <span style="font-family:courier new,courier,monospace;">;(</span><code>Student.prototype = Object.create(Person.prototype</code> في الإصدارات القديمة من جافا سكريبت والتي لا تدعم <code>Object.create</code> يمكن إما استخدام بعض الحيل في خداع المتصفحات –هذه الخدع معروفة إما بالاسم polyfill أو shim—أو استخدام دالة تحقق نفس النتيجة كما في المثال التالي:
</p>

<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
function createObject(proto) {
    function ctor() { }
    ctor.prototype = proto;
    return new ctor();
}

// Usage:
Student.prototype = createObject(Person.prototype);</pre>

<p>
	التأكّد من أن <code>this</code> تُشير إلى الكائن المطلوب بغض النظر عن كيف للكائن أن يُستهل يمكن أن يكون صعبًا، ومع ذلك يوجد صياغة أبسط من شأنها أن تسهّل الأمر.
</p>

<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
var Person = function(firstName) {
  if (this instanceof Person) {
    this.firstName = firstName;
  } else {
    return new Person(firstName);
  }
}</pre>

<h4>
	التغليف Encapsulation
</h4>

<p>
	ليس بالضرورة أن يعلم الصنف <code>Student</code> كيف تمّ تنفيذ/تعريف الطريقة <span style="font-family:courier new,courier,monospace;">()</span><code>walk</code> للصنف <code>Person</code> لكي يستطيع استخدام تلك الطريقة، ولا يحتاج الصنف <code>Student</code> إلى تعريف تلك الطريقة صراحةً إلا إذا كان المطلوب التعديل عليها، ويُطلق على هذا الإجراء مفهوم التغليف encapsulation، والذي فيه يَحزم كل صنف البيانات والطُرق methods داخل وحدة/كينونة وحيدة.
</p>

<p>
	إخفاء المعلومات سمة شائعة في باقي اللغات البرمجية وعادةً ما توجد كخاصيات/كطُرق إما بالاسم <code>private</code> أو <code>protected</code>، وعلى الرغم من أنه يُمكن مماثلة/محاكاة ذات الأمر في جافا سكريبت، إلا أن هذا الأمر ليس مطلبًا من متطلبات البرمجة الكائنية.
</p>

<h4>
	التجريد Abstraction
</h4>

<p>
	التجرير ما هو إلا ميكانيكية تسمح للمطوّر في تجسيد جانب من المشكلة التي يُعمل عليها، إما من خلال الوراثة inheritance (التخصيص specialization) أو التركيب composition، وتُحقق جافا سكريبت التخصيص من خلال الوراثة، والتركيب من خلال السماح لحالات/أمثولات الصنف لتكون قيمًا لخاصيات attributes الكائنات الأخرى.
</p>

<p>
	الصنف Function في جافا سكريبت يرث من الصنف <code>Object</code> (وهذا يوضّح التخصيص في هذا النموذج) والخاصية <code>Function.prototype</code> ما هي إلا حالة/أمثولة من الصنف <code>Object</code> (وهذا يوضّح جزئية التركيب composition).
</p>

<pre class="javascript ipsCode prettyprint" data-pbcklang="javascript" data-pbcktabsize="4">
var foo = function () {};

// logs "foo is a Function: true"
console.log('foo is a Function: ' + (foo instanceof Function));

// logs "foo.prototype is an Object: true"
console.log('foo.prototype is an Object: ' + (foo.prototype instanceof Object));</pre>

<h4>
	تعددية الأشكال Polymorphism
</h4>

<p>
	كما أن جميع الطُرق methods والخاصيات properties معرّفة ضمن الخاصية prototype، فيُمكن لبقية الأصناف أن تُعرِّف طُرقًا methods بنفس الاسم، وستكون الطُرق في نطاق الصنف الذي عُرفت به، إلا إذا كان الصنفان على علاقة من نوع أب وابن parent-child، بمعنى آخر أحد الصنفان يرث من الآخر
</p>

<h2>
	خاتمة
</h2>

<p>
	إن الأساليب التي تم التطرُّق إليها ليست الأساليب الوحيدة التي يمكن استخدامها في تطبيق مفاهيم البرمجة الكائنية في جافا سكريبت، والتي هي مرنة إلى حد كبير في هذا الصدد، ولم تلجئ إلى أي خدع في تطبيق هذه المفاهيم، ولم تقلّد أيضًا الأساليب والنظريات المستخدمة في اللغات الأخرى، وفي جعبة جافا سكريبت العديد من الأساليب الأخرى لتطبيق مفاهيم متقدمة في البرمجة الكائنية التوجّه، ولكن هذه الأساليب المتقدمة هي خارج إطار مقالة تمهيدية، ربما نتطرّق إليها لاحقًا في الأكاديمية.
</p>

<p>
	ترجمة وبتصرّف للمقال <a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript" rel="external nofollow">Introduction to Object-Oriented JavaScript</a>.
</p>

<p>
	 
</p>

<p>
	 
</p>
]]></description><guid isPermaLink="false">179</guid><pubDate>Mon, 28 Sep 2015 22:45:00 +0000</pubDate></item><item><title>&#x625;&#x639;&#x627;&#x62F;&#x629; &#x62A;&#x642;&#x62F;&#x64A;&#x645; Javascript &#x644;&#x645;&#x646; &#x623;&#x633;&#x627;&#x621; &#x641;&#x647;&#x645;&#x647;&#x627;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A5%D8%B9%D8%A7%D8%AF%D8%A9-%D8%AA%D9%82%D8%AF%D9%8A%D9%85-javascript-%D9%84%D9%85%D9%86-%D8%A3%D8%B3%D8%A7%D8%A1-%D9%81%D9%87%D9%85%D9%87%D8%A7-r92/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_06/js-reintro_(1).png.ff1c4b06911538a8c11412b874ad6f8c.png" /></p>

<p>لماذا إعادة تقديم؟ لسوء سُمعة JavaScript حيثُ أنَّها <a rel="external nofollow" href="http://javascript.crockford.com/javascript.html">أكثر لُغة برمجة يُساء فهمها في العالم</a>. على الرَّغم من أنَّه في كثيرٍ من الأحيان يتمّ وصفها لُعبة على سبيل السخريّة، إلَّا أنّهُ أسفل بساطتها الخادعة تقعُ بعض ميزات لغةٍ قويّة، أحدُها أنَّها الآن تُستَخدم من قِبَل عددٍ لا يُصدّق من التطبيقاتِ عاليةِ المستوى، ويُبيِّن ذلك أنَّ معرفةً أعمق بهذه التكنولوجيا إنّما هي مهارة مُهمّة لأي مُطوّر لشبكة الإنترنت أو المحمول.</p><p>من المُفيد أن نبدأ بفكرةٍ عامَّة عن تاريخ هذه اللُّغة. تم إنشاء JavaScript في عام 1995 من قبل Brendan Eich، وهو مهندس في Netscape، وصدرت أولًا مع Netscape 2 في عام 1996. في الأصل كان مُتّفقٌ تسميتها LiveScript، ولكن تمَّ تغيير اسمها في قرارٍ تسويقيٍّ مشؤوم كمُحاولة للاستفادة من شعبية لُغة Java - التابعة لـ  Sun Microsystems- على الرغم من أنَّ هُناك عدد قليل جدًا من القواسم المُشتركة بين اللغتين. لقد كان هذا مصدرًا للارتباك منذ ذلك الحين.</p><p>بعد ثلاثةِ أشهرٍ أطلقت Microsoft نُسخة مُعظمُها مُتوافق مع اللُّغة أسمتها JScript مع IE . قدّمت Netscape اللُّغة إلى <a rel="external nofollow" href="http://www.ecma-international.org/">Ecma International</a>، وهي مُنظّمةُ معاييرٍ أوروبيّة، وأسفرَ ذلك عن الطبعةِ الأولى من ECMAScript القياسيّة في عام 1997. تلقّت اللُغة عملية تحديث كبيرة كما في <a rel="external nofollow" href="http://www.ecma-international.org/publications/standards/Ecma-262.htm">ECMAScript Edition 3</a> في عام 1999، وبَقيتْ مُستقرّة إلى حدٍ كبير منذ ذلك الحين. تمّ التخلي عن الطبعة الرابعة بسبب الخلافات السياسيّة بشأن تعقيد اللُّغة. شكَّلَتْ أجزاءٌ كثيرة من الطبعة الرابعة أساسَ الطبعة ECMAScript 5، التي نُشِرَت في ديسمبر من عام 2009 والطبعة الكبرى 6 والتي سيتمّ نشرها في عام 2015.</p><p>من أجل الاعتياد، سوف أستخدمُ مُصطلحَ JavaScript طوال الوقت.</p><p>خلافًا لمُعظم لغاتِ البرمجة، ليس لدى لغة JavaScript مفهوم الإدخال أو الإخراج. إنّما هي مُصمَّمةٌ لتعمل كلغةِ برمجةٍ نصيّة في بيئة استضافة، والأمرُ متروكٌ للبيئة المضيفة لتوفير آليات للتواصل مع العالم الخارجي. بيئةُ الاستضافةِ الأكثرِ شيوعًا هي المُتصفِّح، ولكن بالإمكان أيضًا العثور على مُفسّر JavaScript في Adobe Acrobat, Photoshop, SVG images, Yahoo!'s Widget engine، فضلًا عن البيئاتِ المُتاحةِ من جانب الخادوم مثل <a rel="external nofollow" href="https://nodejs.org/">node.js</a>. إلا أن قائمة المناطق حيث يتم استخدام JavaScript فقط تبدأ هُنا. تشتملُ اللُّغة أيضًا على قواعد بيانات NoSQL، مثل <a rel="external nofollow" href="http://couchdb.apache.org/">Apache CouchDB</a> مفتوح المصدر، أجهزة الحاسوب المضمّنة أو بيئات سطح المكتب كاملة، مثل <a rel="external nofollow" href="http://www.gnome.org/">GNOME</a> (واحدة من واجهات المستخدم الرسوميّة الأكثر شعبيّة لأنظمة التشغيل جنو / لينكس).</p><h2>نظرة عامة</h2><p>JavaScript هي لغة ديناميكيّة كائنيّة المنحنى. لديها أنواع types ومُشغِّلين operators، كائنات objects قياسيّة مُدمجة ووظائف methods. يأتي بناءُ الجُملةِ في JavaScript من لُغَتَي Java و C، وتنطبقُ العديدُ من الهياكل في تلك اللغات في JavaScript كذلك. إلَّا أنَّ أحد الفروق الرئيسيَّة هو أنَّه لا توجد فئات Classes في JavaScript. بدلًا من ذلك، يتم إنجاز وظائف الفئة عن طريق نماذج الكائن object prototypes. الفرقُ الرئيسي الآخر هو أن الدوال functions هي كائنات، تُعطى الدوال القدرة على الاحتفاظ بتعليماتٍ برمجيَّة قابلة للتنفيذ وتمريرها مثلها مثل أي كائن آخر. دعونا نبدأ من خلال النَّظر داخل لبنة بناء أي لغة: الأنواع. تقوم برامج JavaScript بمُعالجة القيم، وتنتمي كل تلك القيم إلى نوع. أنواع JavaScript هي:</p><ul><li><a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number">عدد Number</a></li><li><a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String">سلسلة String</a></li><li><a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean">منطقيَّة Boolean</a></li><li><a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function">دالّة Function</a></li><li><a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object">كائن Object</a></li><li><a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol">رمز Symbol</a> (جديد في الإصدار 6)</li></ul><p>كذلك <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined">undefined</a> و<a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null">null</a>، ويُعتبر هذين النوعين غريبين بعض الشيء. وهُناكَ أيضًا <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array">المصفوفة Array</a>، والتي هي نوع خاص من الكائن. و<a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date">التاريخ Date</a> و<a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp">المُنشئ RegExp</a>، وهي كائناتٌ تحصلُ عليها مجانًا. ولكي نكون دقيقين من الناحية الفنيّة، الدوال ما هي إلَّا نوعٌ خاصٌّ من الكائن. ولذلك فإن الرسم البياني للنوع يبدو أكثر مثل ما يلي:</p><ul><li><a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number">عدد Number</a></li><li><a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String">سلسلة String</a></li><li><a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Boolean">منطقيَّة Boolean</a></li><li><a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Symbol">رمز Symbol</a> (جديد في الإصدار 6)</li><li><a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object">كائن Object</a><ul><li><a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function">دالّة Function</a></li><li><a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array">مصفوفة Array</a></li><li><a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date">تاريخ Date</a></li><li><a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp">مُنشئ RegExp</a></li></ul></li><li><a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null">لا شيء Null</a></li><li><a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined">غير مُحدَّد Undefined</a></li></ul><p>كذلك هُناك بعض أنواع <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Error">الخطأ Error</a> المُدمجة. لكن على كلِّ حال الأمور أسهل كثيرًا إذا اعتمدنا على الرسم البياني الأوَّل.</p><h2>الأرقام</h2><p>الأرقام في JavaScript هي "قِيَم IEEE 754 الدقيقة المُزدوجة في شكل 64-بِت"، وفقًا للمواصفات. لهذا المعنى بعض العواقب المُثيرة للاهتمام. ليس هُناكَ شيءٌ في JavaScript يُشبه العدد الصحيح integer، لذلك عليك أن تكون حذرًا قليلًا مع عمليّاتك الحسابيّة إذا كنتَ معتادًا على الرياضيات في C أو Java. احترس من أشياء مثل:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">0.1 + 0.2 == 0.30000000000000004</pre><p>في المُمَارسة العمليّة، يتمّ التعامل مع القيم كما أعداد صحيحة من 32 بِت bit (ويتم تخزينهم بتلك الطريقة في بعض تطبيقات المُتصفِّح)، والتي يمكن أن تكون هامّة للعمليّات التي تستخدم نوع بِت.</p><p><a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators#Arithmetic_operators">العوامل الحسابيّة</a> القياسيّة مدعومة، بما في ذلك الجمع والطرح ومُعامل الحساب modulus أو (remainder)، وهكذا دواليك. هناك أيضًا كائن مُدمَج نسيتُ ذِكرَهُ سلفًا يُسمّى <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Math">Math</a> والذي يُمكنكَ استخدامَهُ إذا كنت ترغب في أداءِ دوالٍّ وثوابت رياضيّة أكثر تقدمًا:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">Math.sin(3.5);
var d = Math.PI * r * r;</pre><p>يُمكنكَ تحويل سلسلة إلى عدد صحيح باستخدام الدالّة المُدمجة ()<a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt">parseInt</a>. هذه الدالّة تأخذ قاعدة للتحويل كمُعامِل argument ثاني اختياري، والتي ينبغي عليكَ توفيرها دائمًا:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">parseInt("123", 10); // 123
parseInt("010", 10); // 10</pre><p>رُبَّما تحصُل على نتائج مُذهلة في المُتصفِّحات القديمة (قبل عام 2013) إذا لم توفِّر قاعدة التحويل:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">parseInt("010"); // 8</pre><p>حَدَثَ ذلك لأن دالّة ()<a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt">parseInt</a> قرّرت مُعامَلة السلسلة كثُمانيّة octal نظرًا لأن 0 هي الرَّائدة. إذا كُنتَ ترغب في تحويل رقم ثنائيّ binary إلى عدد صحيح integer، فقط يتمّ تغيير القاعدة:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">parseInt("11", 2); // 3</pre><p>وبالمثل، يمكن تحليل أرقام الفاصِلة العائمة floating point numbers باستخدام الدالّة المُدمجة ()<a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseFloat">parseFloat</a> والتي تَستَخدِم base 10 دائمًا خلافًا لرفيقتها ()<a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt">parseInt</a>. يُمكنكَ أيضًا استخدام عامل التشغيل الأحاديّ + لتحويل القيم إلى أرقام:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">+ "42"; // 42</pre><p>يتمّ إرجاع قيمة خاصّة تُسمّى <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/NaN">NaN</a> (اختصار لـ”Not a Number”) إذا كانت السلسلة غير رقميّة:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">parseInt("hello", 10); // NaN</pre><p>NaN سامّة: إذا قُمتَ بتقديمها كمدخل input إلى أي عمليَّة حسابيَّة فإن النتيجة ستكون أيضًا NaN:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">NaN + 5; // NaN</pre><p>يُمكنكَ اختبار NaN باستخدام الدالّة المُدمجة ()<a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isNaN">isNaN</a>:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">isNaN(NaN); // true</pre><p>لدى JavaScript القيم الخاصّة <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Infinity">Infinity</a> و-Infinity:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">1 / 0; //  Infinity
-1 / 0; // -Infinity</pre><p>يُمكنكَ اختبار قيم Infinity و–Infinity وNaN باستخدام الدالّة المُدمجة ()<a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/isFinite">isFinite</a>:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">isFinite(1/0); // false
isFinite(-Infinity); // false
isFinite(NaN); // false</pre><p>مُلاحظة: تقوم دالَّتَي ()<a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseInt">parseInt</a> و()<a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/parseFloat">parseFloat</a> بتحليل سلسلة حتى تصلا إلى حرفٍ غير صالح لشكل الرَّقم المُحدَّد، بعد ذلك يتمّ إرجاع الرقم الذي تم تحليله إلى تلك النقطة. رغم ذلك فإن المُعامِل "+" يقوم ببساطة بتحويل السلسلة إلى NaN إذا كان هُناك أيّ حرفٍ غير صالح في السلسلة. جرّب محاولة تحليل السلسلة "10.2abc" باستخدام كل طريقة مع نفسك في وحدة التَّحكُّم console، وسوف تفهم الاختلافات بشكلٍ أفضل.</p><h2>السلاسل</h2><p>السلاسل في JavaScript هي مُتتابعات من الأحرف. ولتعريفٍ أكثر دقة، هي مُتتابعات من <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Values,_variables,_and_literals#Unicode">أحرف Unicode</a>، يتمّ تمثيل كُل حرف في عدد 16 بِت. لا بُدَّ أنَّ هذا نبأ سار لأي شخص قد تعامل مع نظام التدويل. إذا كُنتَ ترغب في تمثيل حرف واحد، عليكَ استخدام سلسلة من طول 1 فقط. للعثور على طول سلسلة، قٌم باستدعاء خاصيّتها <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/length">length</a>:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">"hello".length; // 5</pre><p>هذه أول فُرشاة لدينا مع كائنات JavaScript! هل ذكرتُ لكَ أنَّ بامكانكَ استخدام السلاسل مثل <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object">الكائنات</a> أيضًا؟ لديهم <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String#Methods">وظائف</a> تسمحُ لكَ بمُعالجة السلسلة والوصول إلى معلومات عنها:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">"hello".charAt(0); // "h"
"hello, world".replace("hello", "goodbye"); // "goodbye, world"
"hello".toUpperCase(); // "HELLO"</pre><h2>أنواع أخرى</h2><p>تُميّز JavaScript ما بين <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/null">null</a>، وهي القيمة التي تدل على لا شيء (ويمكن الوصول إليها من خلال طريقة واحدة ألا وهي استخدام الكلمة المحجوزة null)، و<a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/undefined">undefined</a>، وهي قيمة من نوع 'غير معروف' التي تُشير إلى قيمة غير مُهيَّأة - أي قيمة لم يتمّ تعيينها بعد. سوف نتحدَّث عن المُتغيّرات في وقتٍ لاحق، ولكن يُمكن تعريف مُتغيّر في JavaScript دون تحديد قيمة له. إذا قمتَ بذلك، فإنَّ نوع المُتغيّر يُصبِح undefined. في الواقع نوع undefined ثابت.</p><p>لدى JavaScript نوع Boolean مع القيم الممكنة true وfalse (وكلاهما كلمات محجوزة). يمكن تحويل أيّ قيمة إلى قيمة منطقيّة وفقًا للقواعد التالية:</p><p>1- تُصبِح كل من (false، 0، سلسلة فارغة (<span style="font-family:courier new,courier,monospace;">" "</span>)، NaN، null وundefined) false. 2- تُصبِح كل القيم الأخرى true.</p><p>يُمكنكَ إجراء هذا التحويل صراحة باستخدام دالَّة ()Boolean:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">Boolean("");  // false
Boolean(234); // true</pre><p>ولكن نادرًا ما يكون هذا ضروريًّا، حيث أن JavaScript ستؤدّي بصمتٍ هذا التحويل عندما تتوقَّع قيمة منطقيَّة، مثل في عبارة if (انظر أدناه). لهذا السبب، ببساطة نذكُر أحيانًا "القيم الحقيقيّة" و"القيم الزائفة" قاصدين القيم التي تُصبح true وfalse على التوالي عند تحويلها إلى القيم المنطقيّة. بدلًا من ذلك يُمكن تسمية هذه القيم "truthy" و"falsy" على التوالي. العمليّات المنطقيّة مثل &amp;&amp;، logical and) || (logical or و! (logical not) مُعتمَدة. انظر أدناه.</p><h2>المُتغيّرات</h2><p>يتمّ تعريف المُتغيّرات الجديدة في JavaScript باستخدام <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/var">var</a>:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">var a;
var name = "simon";</pre><p>إذا قمتً بتعريف مُتغيّر دون تعيين أيّ قيمة له، فإن نوعه يُصبِح undefined. هناك فارق هام عن لغات أخرى مثل Java ألا وهو أنّ الكُتَل blocks في JavaScript لا تملك نطاق scope؛ فقط الدوال هي التي لها نطاق. لذلك إذا تم تعريف مُتغيّر باستخدام var في جملة مُجمّعة (على سبيل المثال داخل if control structure)، سيكون المُتغيِّر مرئي من قِبَل الدالّة كاملة. إلَّا أنَّه بدءًا من ECMAScript الطبعة 6، تَسمحُ لك تعريفات <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let">let</a> و<a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const">const</a> امكانيَّة إنشاء مُتغيّرات block-scoped.</p><h2>المُعامِلات</h2><p>مُعامِلات JavaScript الرقميّة هي +، -، *، / و٪ - وهو عامل ما تبقى. يتمّ تعيين القيم باستخدام = وهناك أيضًا جُمل تعيين مُركبّة مهمّة مثل += و-=. هذه تمتد إلى x = x مُعامِل y.</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">x += 5
x = x + 5</pre><p>يُمكنكَ استخدام ++ و-- للزيادة والإنقاص على التوالي. كذلك بإمكانك أن تَستَخدِم هذه المُعامِلات كمُعامِلات prefix أو postfix. يقومُ <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Arithmetic_Operators#Addition">المُعامِل +</a> بربط السلسلة:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">"hello" + " world"; // "hello world"</pre><p>إذا قمتَ بإضافة سلسلة لعدد (أو قيمة أخرى) يتمّ تحويل كل شيء إلى سلسلة أولًا. يُمكن لما يلي أن يوضِّح المقصود:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">"3" + 4 + 5;  // "345"
 3 + 4 + "5"; // "75"</pre><p>إضافة سلسلة فارغة إلى شيء هي وسيلة مفيدة لتحويله إلى سلسلة. يُمكن إجراء <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Comparison_Operators">المُقارنات</a> في JavaScript باستخدام &lt;، &gt;، &lt;= و =&gt;. تَعمَلُ هذه المُقارنات مع السلاسل والأرقام على حدٍّ سواء. تبدو المُساواة أوضح قليلًا عن نظيراتها. تقوم المُساواة المزدوجة == بإجبار تغيير النَّوع إذا قُمتَ باعطائها أنواع مختلفة، وتُعطي نتائج مُثيرة للاهتمام في بعض الأحيان:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">"dog" == "dog"; // true
1   == true; // true</pre><p>لتجنُّب إجبار النَّوع، استخدم المساواة الثلاثيَّة:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">1 === true;    // false
true === true; // true</pre><p>هُناكَ أيضًا != و!==. لدى JavaScript أيضًا <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Bitwise_Operators">مُعامِلات أُحاديّة</a>. إذا كنت ترغب في استخدامها.</p><h2>هياكل التَّحكُّم</h2><p>لدى JavaScript مجموعة مُماثِلة لهياكل التَّحكُّم الموجودة في لغات أخرى مثل عائلة C. العبارات الشرطيَّة مدعومة بواسطة if وelse؛ يُمكنكَ سَلسَلَتهم معًا إذا أردت:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">var name = "kittens";
if (name == "puppies") {
  name += "!";
} else if (name == "kittens") {
  name += "!!";
} else {
  name = "!" + name;
}
name == "kittens!!"</pre><p>لدى JavaScript حلقات while وحلقات do-while. الأولى جيِّدة لعمليات الحلقات البسيطة؛ والثانية مع تلك الحلقات إذا كنت ترغب في التأكُّد من أن جسد الحلقة يتمّ تنفيذه مرة واحدة على الأقل:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">while (true) {
  // an infinite loop!
}

var input;
do {
  input = get_input();
} while (inputIsNotValid(input))</pre><p>For loop في JavaScript هي نفسها التي في C وJava: فهي تُتيح لكَ توفير معلومات التَّحكُّم للحلقة الخاصّة بك في سطرِ واحد.</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">for (var i = 0; i &lt; 5; i++) {
  // Will execute 5 times
}</pre><p>يَستخدم المُعامِلين &amp;&amp; و|| دائرة منطقيَّة قصيرة، وهو ما يعني أنَّها تعتمد على مُعامِلها الأوّل في إذا ما كانت ستُنفِّذ مُعامِلها الثاني. وهذا مُفيد لفحص الكائنات الفارغة قبل محاولة الوصول إلى سماتها:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">var name = o &amp;&amp; o.getName();</pre><p>أو لوضع قيم افتراضيّة:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">var name = otherName || "default";</pre><p>لدى JavaScript مُعامِل ثُلاثي للتعبيرات الشرطيَّة:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">var allowed = (age &gt; 18) ? "yes" : "no";</pre><p>يُمكن استخدام جُملة switch مع الفروع المتعدِّدة استنادًا إلى عددٍ أو سلسلة:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">switch(action) {
  case 'draw':
    drawIt();
    break;
  case 'eat':
    eatIt();
    break;
  default:
    doNothing();
}</pre><p>إذا لم تقم بإضافة break سوف يتوقّف التنفيذ عن المستوى التالي. وهذا نادرًا جدًا ما تُريد أن يحدث - في واقع الأمر هي تستحقّ وصفها على وجه التحديد fallthrough في تعليق إذا كُنتَ حقَا من المفترض أن تساعد في التصحيح:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">switch(a) {
  case 1: // fallthrough
  case 2:
    eatIt();
    break;
  default:
    doNothing();
}</pre><p>يُعتبر شرط default اختياري. يُمكنكَ الحااق تعبيرات في كل من جزء switch وcase إذا أردت ذلك. تُجرَي المُقارنات بين اثنين باستخدام ===:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">switch(1 + 3) {
  case 2 + 2:
    yay();
    break;
  default:
    neverhappens();
}</pre><h2>الكائنات</h2><p>يُمكن اعتبار كائنات JavaScript كمجموعات بسيطة من أزواج name-value. على هذا النحو يمكن تشبيهها بـ: * القواميس Dictionaries في لغة Python * التجزئات Hashes في لغتي Perl وRuby * جداول التجزئة Hash Tables في لغتي C و C++ * HashMaps في لغة Java * مصفوفات الترابط Associative arrays في لغة PHP</p><p>حقيقة أنّ هياكل البيانات تُستخدم في نطاق واسع ما هو إلَّا دليلٌ على تنوُّعها. وحيثُ أنَّ كل شيء (أنواع الشريط الأساسيَّة bar core types) في JavaScript هو كائن، فإنَّ أيّ برنامج JavaScript يحتوي بطبيعة الحال على قدرٍ كبيرٍ من عمليَّات البحث في جدول التجزئة. وهذا شيءٌ جيِّد والعمليَّات سريعة جدًا!</p><p>جزء الـ"اسم" هو سلسلة JavaScript، في حين أنَّ القيمة يُمكن أن تكون أي قيمة لـ JavaScript - بما في ذلك المزيد من الكائنات. يَسمحُ هذا لك بامكانيَّة بناء هياكل بيانات من نوع التعقيد التعسُّفي.</p><p>هُناكَ طريقتان أساسيَّتان لإنشاء كائن فارغ:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">var obj = new Object();</pre><p>و:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">var obj = {};</pre><p>و:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">function Person(name, age) {
  this.name = name;
  this.age = age;
}

// Define an object
var You = new Person("You", 24); 
// We are creating a new person named "You" 
// (that was the first parameter, and the age..)</pre><p>هذه الطُرق مُتعادِلة لغويًّا؛ يُطلق على الثانية جُملة الكائن الحرفيّة، وهي الأكثر ملاءمة. بناء الجملة هذه هو أيضًا جوهر شكل JSON لذلك ينبغي تفضيل استخدامها في جميع الأوقات.</p><p>يُمكن الوصول إلى سِمَات الكائن بمُجرّد إنشائه بطريقة من اثنتين:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">obj.name = "Simon";
var name = obj.name;</pre><p>و:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">obj["name"] = "Simon";
var name = obj["name"];</pre><p>هاتين الطريقتين مُتعادِلتين لُغويًا أيضًا. للطريقة الثانية ميزة ألا وهي أنَّ اسم الصفة المُميّزة property يتم توفيره كسلسلة، مما يعني أنَّه يُمكن حسابها في وقت التشغيل. رغم ذلك استخدام هذا الأسلوب يمنع بعض تحسينات مُحرِّك ومُصغِّر حجم JavaScript من التطبيق. أيضًا لتحديد set والحصول على get يُمكِنُكَ استخدام الخصائص ذات الأسماء المُتعارَف على أنَّها <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar#Keywords">كلمات محجوزة</a>:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">obj.for = "Simon"; // Syntax error, because 'for' is a reserved word
obj["for"] = "Simon"; // works fine</pre><p>مُلاحظة: ابتداءً من EcmaScript 5، يُمكن استخدام الكلمات المحجوزة كأسماء خاصيّة الكائن المُميّزة object property مُجرّدة، وهذا يُعني أنَّها لا تحتاج إلى أن يتمّ وضعها بين اقتباسات عند تحديد حرفيَّات الكائن. راجع ES5 في <a rel="external nofollow" href="http://es5.github.io/#x7.6.1">Spec</a>.</p><p>يُمكن استخدام جُملة الكائن الحرفيّة لتهيئة كائن في مُجمَله:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">var obj = {
  name: "Carrot",
  "for": "Max",
  details: {
    color: "orange",
    size: 12
  }
}</pre><p>يُمكن سَلسَلة الوصول إلى الخاصيّة المُميّزة معًا:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">obj.details.color; // orange
obj["details"]["size"]; // 12</pre><h2>المصفوفات</h2><p>في الواقع المصفوفات في JavaScript هي نوعٌ خاصٌّ من الكائن. تعملُ المصفوفات كثيرًا مثل الأشياء العاديّة (يُمكن الوصول إلى الخصائص العدديّة باستخدام صياغة [] فقط) ولكن لدى المصفوفات خاصيَّة سحريَّة تُسمَّى ‘length’. هذه الخاصيَّة دائمًا ما تَزِيد بواحد عن أعلى مؤشِّر في المصفوفة.</p><p>هُناك طريقة واحدة لخلق المصفوفات وهي على النحو التالي:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">var a = new Array();
a[0] = "dog";
a[1] = "cat";
a[2] = "hen";
a.length; // 3</pre><p>هُناك تأشير أكثر ملاءمة ألا وهو استخدام المصفوفات الحرفيَّة:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">var a = ["dog", "cat", "hen"];
a.length; // 3</pre><p>لاحظ أن array.length ليس بالضرورة عدد العناصر في المصفوفة. مع مراعاة ما يلي:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">var a = ["dog", "cat", "hen"];
a[100] = "fox";
a.length; // 101</pre><p>تذكَّر - طول المصفوفة يزيد بواحد عن أعلى مؤشِّر بها. إذا استعلمتَ عن مؤشِّر مصفوفة غير موجود، تحصل على نوع غير مُعرَّف undefined:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">typeof a[90]; // undefined</pre><p>إذا أخذتَ ما سبق في الاعتبار، يمكنك التكرار عبر مصفوفة باستخدام ما يلي:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">for (var i = 0; i &lt; a.length; i++) {
  // Do something with a[i]
}</pre><p>هذه الطريقة غير فعّالة بعض الشيء حيثُ أنّكَ تقوم بالبحث عن الخاصيَّة length مرّة واحدة كل حلقة. تحسينٌ لهذا ما يلي:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">for (var i = 0, len = a.length; i &lt; len; i++) {
  // Do something with a[i]
}</pre><p>هذا أجمل في المظهر ولكن ذو لغة محدودة:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">for (var i = 0, item; item = a[i++];) {
  // Do something with item
}</pre><p>نقوم هُنا بإعداد مُتغيّرين. يتم اختبار التعيين أيضًا في الجزء الأوسط من الحلقة للتأكُّد من المصداقيّة - إذا نَجَحَت، ستستمرّ الحلقة في العمل. وحيثُ أن i يتزايد في كل مرّة، سيتمّ تعيين العناصر من المصفوفة إلى عناصر في ترتيب تسلسلي. تتوقّف الحلقة عندما يتمّ العثور على قيم "falsy" (مثل نوع undefined).</p><p>يجبُ عليكَ استخدام هذه الحيلة فقط مع المصفوفات التي تَعْلَمُ أنَّها لا تحتوي على قِيَم "falsy" (على سبيل المثال مصفوفات من كائنات أو نموذج كائن المُستند DOM). إذا كُنتَ تقوم بالتكرار خلال بيانات رقميَّة يُمكن أن تشمل 0 أو بيانات سلسلة يُمكن أن تشمل سلسلة فارغة يجبُ عليكَ بدلًا من ذلك استخدام تعبير i, len.</p><p>هُناك طريقة أخرى للتكرار وهي استخدام حلقة <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for...in">for…in</a>. لاحظ أنَّهُ إذا قامَ شخصٌ بإضافة خصائص جديدة لـ Array.prototype فإنَّه سيتم تكرارهم من قِبَل هذه الحلقة أيضًا:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">for (var i in a) {
  // Do something with a[i]
}</pre><p>إذا كُنتَ ترغب في إلحاق عنصر إلى مصفوفة، ببساطة قُم بذلك كما يلي:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint" dir="ltr">a.push(item);</pre><p>تأتي المصفوفات مع عدد من الوظائف. انظر أيضًا <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array">وثائق كاملة عن أساليب المصفوفة</a>.</p><table><thead><tr><th style="text-align:right">الوصف</th><th style="text-align:left">اسم الدالَّة</th></tr></thead><tbody><tr><td style="text-align:right">تقوم بإرجاع سلسلة مع toString() من كل عنصر مفصولة بفواصل.</td><td style="text-align:left" dir="ltr">a.toString()</td></tr><tr><td style="text-align:right">تقوم بإرجاع سلسلة مع toLocaleString() من كل عنصر مفصولة بفواصل.</td><td style="text-align:left" dir="ltr">a.toLocaleString()</td></tr><tr><td style="text-align:right">تقوم بإرجاع مصفوفة جديدة مع عناصر مضافة إليها.</td><td style="text-align:left" dir="ltr">a.concat(item1[, item2[, ...[, itemN]]])</td></tr><tr><td style="text-align:right">تقوم بتحويل المصفوفة إلى سلسلة - قيم محدَّدة من قبل العامل المُتغيِّر sep</td><td style="text-align:left" dir="ltr">a.join(sep)</td></tr><tr><td style="text-align:right">تقوم بإزلة وإرجاع العنصر الأخير.</td><td style="text-align:left" dir="ltr">a.pop()</td></tr><tr><td style="text-align:right">تقوم push بإضافة عنصر واحد أو أكثر في النهاية.</td><td style="text-align:left" dir="ltr">a.push(item1, ..., itemN)</td></tr><tr><td style="text-align:right">تقوم بعكس المصفوفة.</td><td style="text-align:left" dir="ltr">a.reverse()</td></tr><tr><td style="text-align:right">تقوم بإزالة وإعادة العنصر الأول.</td><td style="text-align:left" dir="ltr">a.shift()</td></tr><tr><td style="text-align:right">تقوم بإرجاع مصفوفة فرعيَّة (Sub-array).</td><td style="text-align:left" dir="ltr">a.slice(start, end)</td></tr><tr><td style="text-align:right">تقوم بأخذ دالَّة مقارنة اختياريَّة.</td><td style="text-align:left" dir="ltr">a.sort([cmpfn])</td></tr><tr><td style="text-align:right">تتيح لك تعديل مصفوفة عن طريق حذف قسم واستبداله بمزيد من العناصر.</td><td style="text-align:left" dir="ltr">a.splice(start, delcount[, item1[, ...[, itemN]]])</td></tr><tr><td style="text-align:right">تقوم بإلحاق عناصر إلى بداية المصفوفة.</td><td style="text-align:left" dir="ltr">a.unshift([item])</td></tr></tbody></table><p> </p><h2>الدوالّ</h2><p>الدوالّ هي العنصر الأساسيّ في فهم JavaScript جنبًا إلى جنبٍ مع الكائنات. لا يُمكن للدالّة المُجرّدة أن تكون أسهل من التالية:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">function add(x, y) {
  var total = x + y;
  return total;
}</pre><p>تدلُّ التعليمات البرمجيَّة هذه على كل شيء يُمكن معرفته عن الدوال الأساسية. يُمكن لدالّة JavaScript أن تستقبل 0 أو أكثر مما تُدعى مُتغيّرات. يُمكن لجسم الدالّة أن يحتوي على عدد ما تُريد من الجُمل statements، ويُمكن أن تُعرّف مُتغيّراتُها الخاصّة والتي تكون محليّة بالنسبة لتلك الدالّة. يُمكن استخدام جُملة return لإرجاع قيمة في أي وقت ثُمَّ إنهاء الدالّة. إذا لم يتمّ استخدام أيّ جُملة إرجاع (أو تمّ استخدامها وكانت فارغة بدون قيمة) فإن JavaScript تقوم بإرجاع نوع 'غير مُعرَّف'.</p><p>تُعتبر المُتغيّرات المُسمّاه كمبادئ توجيهيّة أكثر من أي شيء آخر. يُمكنكَ استدعاء دالّة دون تمرير المُتغيّر الذي تتوقّعه الدالّة، في هذه الحالة سيتمّ تعيين المُتغيّر كنوع غير مُعرَّف.</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">add(); // NaN 
// You can't perform addition on undefined</pre><p>يُمكنكَ أيضًا تمرير عدد من المُتغيّرات أكثر من العدد الذي تتوقّعه الدالّة:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">add(2, 3, 4); // 5 
// added the first two; 4 was ignored</pre><p>قد يبدو هذا سخيفًا بعض الشيء ولكن لدى الدوال خاصيَّة الوصول إلى مُتغيّرات إضافيّة داخل أجسامهم تُسمّى <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/arguments">arguments</a>، والتي هي كائن مثل المصفوفة تحتوي على كافّة القيم التي تمَّ تمريرُها إلى الدالّة. دعونا نُعيد كتابة دالّة الجمع لتأخذ عدد ما نُريد من القيم:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">function add() {
  var sum = 0;
  for (var i = 0, j = arguments.length; i &lt; j; i++) {
    sum += arguments[i];
  }
  return sum;
}

add(2, 3, 4, 5); // 14</pre><p>رغم ذلك فإنَّ هذا في الحقيقة ليس له أيّ فائدة على مُجرَّد كتابة 2 + 3 + 4 + 5. دعونا نقوم بإنشاء دالّة المتوسِّط:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">function avg() {
  var sum = 0;
  for (var i = 0, j = arguments.length; i &lt; j; i++) {
    sum += arguments[i];
  }
  return sum / arguments.length;
}

avg(2, 3, 4, 5); // 3.5</pre><p>هذا مفيدٌ جدًا ولكنَّه يُظهِر مُشكلة جديدة. تأخذ دالّة <span style="font-family:courier new,courier,monospace;">()avg</span> قائمة من المُتغيّرات مفصولٌ بينَ كلٍّ منها بفاصِلة - ولكن ماذا لو كُنتَ تُريد أن تجد مُتوسّط مصفوفة؟ يُمكنك كتابة الدالّة على النحو التالي:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">function avgArray(arr) {
  var sum = 0;
  for (var i = 0, j = arr.length; i &lt; j; i++) {
    sum += arr[i];
  }
  return sum / arr.length;
}

avgArray([2, 3, 4, 5]); // 3.5</pre><p>سيكونُ من الجميل أن يُصبح بمقدورِنا إعادة استخدام الدالَّة التي قُمنا بإنشائِها مُسبقًا. لحُسن الحظّ، تُمكنُّكَ Javascript من استدعاء دالّة مع مصفوفة من قيم المُتغيّرات العشوائيّة، وذلكَ باستخدام وظيفة <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/apply">apply()</a> من أي كائن دالّة.</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">avg.apply(null, [2, 3, 4, 5]); // 3.5</pre><p>قيمة المُتغيّر الثانية لـ <span style="font-family:courier new,courier,monospace;">()apply</span> هي المصفوفة المُستخدمة كقيم المُتغيّرات؛ سيتم نقاش المُتغيّر الأول في وقت لاحق. هذا يؤكد حقيقة أن الدوالّ هي كائنات أيضًا.</p><p>تُتيح لكَ Javascript إنشاء وظائف مجهولة.</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">var avg = function() {
  var sum = 0;
  for (var i = 0, j = arguments.length; i &lt; j; i++) {
    sum += arguments[i];
  }
  return sum / arguments.length;
}</pre><p>هذا هو ما يُعادل لُغويًا نموذج دالّة <span style="font-family:courier new,courier,monospace;">()avg</span>. إنَّها قويَّة للغاية حيثُ أنها تُتيحُ لكَ وضع تعريف دالَّة كاملة في أي مكان يُمكنكَ عادة وضع تعبير expression به. يُتيحُ هذا كل أنواع الحِيَل. إليكَ طريقة لـ "اخفاء" بعض المُتغيّرات المحليّة – مثل نطاق الكتلة block scope في لغة C:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">var a = 1;
var b = 2;

(function() {
  var b = 3;
  a += b;
})();

a; // 4
b; // 2</pre><p>تسمحُ لكَ JavaScript استدعاء دوال بشكلٍ متكرِّر. هذا الأمرُ مفيدٌ بشكلِ خاصّ في التعامل مع هياكل الشجرة tree structures، مثل ما تحصُلُ عليه في نموذج كائن المُستند DOM بالمُتصفّح.</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">function countChars(elm) {
  if (elm.nodeType == 3) { // TEXT_NODE
    return elm.nodeValue.length;
  }
  var count = 0;
  for (var i = 0, child; child = elm.childNodes[i]; i++) {
    count += countChars(child);
  }
  return count;
}</pre><p>هذا يُسلّط الضَوْء على مشكلةٍ مُحتملةٍ مع الدوال المجهولة: كيف يُمكن استدعاؤها بشكلِ متكرر إذا لم يكُن لديها اسم؟ تُتيحُ لكَ JavaScript تسمية تعبيرات دالَّة لهذا الغرض. يُمكنكَ استخدام تعبيرات تنفيذ الدالَّة مُباشرةً (IIFEs - Immediately Invoked Function Expressions) المُسمّاة على النحو التالي:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">var charsInBody = (function counter(elm) {
  if (elm.nodeType == 3) { // TEXT_NODE
    return elm.nodeValue.length;
  }
  var count = 0;
  for (var i = 0, child; child = elm.childNodes[i]; i++) {
    count += counter(child);
  }
  return count;
})(document.body);</pre><p>الاسم المُقدّم إلى تعبير دالّة على النحو الوارد أعلاه إنَّما هو متاحٌ فقط لنطاقِ الدالّة نفسها. يَسمحُ هذا بمزيدِ من التحسينات تُنفَّذ من قِبَل المُحرِّك وتعليمات برمجيَّة أكثرُ قابليَّة للقراءة على حدٍّ سواء. يظهر الاسم أيضًا في المُصَحِّح debugger وبعض stack trace التي يمكن أن تُوفِّر لكَ الوقت.</p><p>لاحظ أن دوالّ JavaScript هي نفسها كائنات ويُمكنكَ إضافة أو تغيير خصائص بها تمامًا مثل الكائنات الّتي تطرَّقنا إليها في جُزء الكائنات.</p><h2>الكائنات المُخصَّصَة</h2><p>مُلاحظة: للاطّلاع على نقاش أكثر تفصيلًا عن البرمجة الشيئيَّة في JavaScript، انظر <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Introduction_to_Object-Oriented_JavaScript">مُقدِّمة إلى JavaScript الشيئيّة</a>.</p><p>في البرمجة الشيئيّة الكلاسيكيّة، الكائنات هي مجموعات من بيانات ووظائف تعملُ على تلك البيانات. JavaScript هي لغة النموذج القائم والتي لا تحتوي على فئات مثل تِلكَ التي توجد في C++ أو Java. (هذا الامرُ مُربِك أحيانًا للمبرمجين مِمَّن اعتادوا على لغات تحتوي على فئات.) بدلًا من ذلك تَستَخدِم JavaScript الدوال كفئات. لنعتبر أن هُناك كائن عبارة عن شخص Person لديه حقلي الاسم الأول والاسم الأخير. هُناك نوعان من الطرق التي من خلالها قد يتمّ عرض الاسم: كما "الأوَّل الأخير" أو "الأخير، الأوَّل". هذه طريقة لفعل ذلك باستخدام الدوال والكائنات التي ناقشناها سابقًا:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">function makePerson(first, last) {
  return {
    first: first,
    last: last
  };
}
function personFullName(person) {
  return person.first + ' ' + person.last;
}
function personFullNameReversed(person) {
  return person.last + ', ' + person.first;
}

s = makePerson("Simon", "Willison");
personFullName(s); // "Simon Willison"
personFullNameReversed(s); "Willison, Simon"</pre><p>هذه الطريقة تعمل ولكنَّها سيِّئة جدًا. ينتهي بكَ الأمر مع العشرات من الدوال في مساحتك العامَّة global namespace. ما نحتاجه حقًا هو وسيلة لإرفاق دالَّة بكائن. حيثُ أنَّ الدوال هي كائنات، هذا أمر سهل:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">function makePerson(first, last) {
  return {
    first: first,
    last: last,
    fullName: function() {
      return this.first + ' ' + this.last;
    },
    fullNameReversed: function() {
      return this.last + ', ' + this.first;
    }
  };
}

s = makePerson("Simon", "Willison")
s.fullName(); // "Simon Willison"
s.fullNameReversed(); // "Willison, Simon"</pre><p>هُناك شيء في هذه الجُمل التعليميَّة لم نَرَ من قبل: الكلمة المحجوزة <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/this">this</a>. تُستَخدَم this داخل الدالَّة وتُشير إلى الكائن الحالي. ما يُعنيه ذلك بالتحديد أنه يتمّ التعيين نِتاجًا عن الطريقة التي قُمتَ باستدعاء الدالَّة بها. إذا قمت باستدعائها باستخدام <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Object_initializer#Accessing_properties">تأشير النقطة أو تأشير القوس</a> في كائن، يُصبِح هذا الكائن this. إذا لم يتمّ استخدام تأشير النقطة dot notation للاستدعاء، تُشير this إلى الكائن العام global object.</p><p>لاحظ أن this هي سبب مُتكرِّر للأخطاء. على سبيل المثال:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">s = makePerson("Simon", "Willison");
var fullName = s.fullName;
fullName(); // undefined undefined</pre><p>عندما نستدعي <span style="font-family:courier new,courier,monospace;">()fullName</span> وحدها، من دون استخدام <span style="font-family:courier new,courier,monospace;">()s.fullName</span>، فإنَّ هذا مُقيَّد بالنطاق العام global scope. وبما أنَّه لا توجد مُتغيِّرات عامَّة global variables تُسمَّى first أو last فإنَّنا نحصل على نوع undefined لكلِّ واحد منهما.</p><p>يُمكننا الاستفادة من الكلمة المحجوزة this لتحسين دالَّة makePerson:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">function Person(first, last) {
  this.first = first;
  this.last = last;
  this.fullName = function() {
    return this.first + ' ' + this.last;
  };
  this.fullNameReversed = function() {
    return this.last + ', ' + this.first;
  };
}
var s = new Person("Simon", "Willison");</pre><p>قدَّمنا كلمة محجوزة أُخرى: <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/new">new</a>. ترتبط new ارتباطًا وثيقًا بـ this. ما تفعله هو أنَّها تخلُق كائن فارغ جديد تمامًا، ثم تدعو الدالَّة المُحدَّدة ويتمّ تعيين this لهذا الكائن الجديد. لاحظ أنَّ الدالَّة المُحدَّدة بواسطة this لا تُرجِع قيمة ولكنَّها فقط تقوم بتعديل كائن this. تُرجِع new كائن this إلى موقع الاستدعاء. يُطلَق على الدوال المُصمَّمة ليتمّ استدعاؤها بواسطة new دوال المُنشِئ. مُمارسة شائعة هي كتابة تلك الدوال بأحرف كبيرة كتذكير لاستدعائهم بواسطة new.</p><p>لا يزال لدى الدالَّة المُحسَّنة نفس المأزق مع استدعاء <span style="font-family:courier new,courier,monospace;">()fullName</span> وحدها. بدأت كائنات Person تُصبِح أفضل ولكن لا تزال هُناك بعض الحوافّ السيِّئة لديها. في كل مرة نقوم بإنشاء كائن Person جديد فنحن نقوم بخلق كائني دالَّة جديدين به كذلك - ألن يكون أفضل لو كانت هذه التعليمات البرمجيَّة مُشتَرَكة؟</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">function personFullName() {
  return this.first + ' ' + this.last;
}
function personFullNameReversed() {
  return this.last + ', ' + this.first;
}
function Person(first, last) {
  this.first = first;
  this.last = last;
  this.fullName = personFullName;
  this.fullNameReversed = personFullNameReversed;
}</pre><p>هذا أفضل: نقومُ بخلق دوال الوظيفة مرَّة واحدة فقط، ونُعيِّنُ مراجع لهم داخل المُنشئ. هل بإمكاننا فعل ما هو أفضل من ذلك؟ الجواب هو نعم:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">function Person(first, last) {
  this.first = first;
  this.last = last;
}
Person.prototype.fullName = function() {
  return this.first + ' ' + this.last;
};
Person.prototype.fullNameReversed = function() {
  return this.last + ', ' + this.first;
};</pre><p>Person.prototype هو كائن مُشتَرَك من قِبَل كافَّة نماذج Person. يُشكِّلُ هذا الكائن جُزءًا من سلسلة بحث (لها اسم خاص وهو "سلسلة النموذج" prototype chain): متى حاولتَ الوصول إلى خاصيَّة غير مُعيَّنة في Person، سوف تتحقَّق JavaScript من Person.prototype لترى ما إذا كانت هذه الخاصّيّة موجودة هناك بدلًا من ذلك. نتيجة لذلك، أي شيء مخصَّص لـ Person.prototype يُصبِح متاحًا لجميع النماذج من هذا المُنشئ عبر كائن this.</p><p>هذه أداة قويَّة بشكلٍ لا يُصدَّق حيثُ أنَّ JavaScript تُتيحُ لكَ تعديل نموذج شيء في أيّ وقت في بَرنامجك، ممَّا يُعني أنَّه يُمكنكَ زيادة وظائف إضافيَّة لكائنات موجودة في وقت التَّشغيل:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">s = new Person("Simon", "Willison");
s.firstNameCaps(); // TypeError on line 1: s.firstNameCaps is not a function

Person.prototype.firstNameCaps = function() {
  return this.first.toUpperCase()
};
s.firstNameCaps(); // "SIMON"</pre><p>من المُثير للاهتمام أنَّهُ يُمكنكَ أيضًا إضافة أشياء إلى النموذج الخاصّ بالكائنات المُدمجة في JavaScript. دعونا نُضيف وظيفة إلى سلسلة تقوم بإرجاع هذه السلسلة معكوسة:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">var s = "Simon";
s.reversed(); // TypeError on line 1: s.reversed is not a function

String.prototype.reversed = function() {
  var r = "";
  for (var i = this.length - 1; i &gt;= 0; i--) {
    r += this[i];
  }
  return r;
};

s.reversed(); // nomiS</pre><p>تعمل الطَّريقة الجديدة حتَّى مع حرفيَّات السلسلة string literals</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">"This can now be reversed".reversed(); // desrever eb won nac sihT</pre><p>كما ذكرتُ سالِفًا، يُشكِّل النموذج جزءًا من سلسلة. جذر تلك السلسلة هو Object.prototype والذي من وظائفه <span style="font-family:courier new,courier,monospace;">()toString</span> - تلك هي الوظيفة التي يتمّ استدعاؤها عندما تُحاول تمثيل كائن كسلسلة. يُعتبَر هذا مفيدًا من أجل تصحيح كائنات Person:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">var s = new Person("Simon", "Willison");
s; // [object Object]

Person.prototype.toString = function() {
  return '&lt;Person: ' + this.fullName() + '&gt;';
}

s; // "&lt;Person: Simon Willison&gt;"</pre><p>أتذكُرُ كيف احتَوَت <span style="font-family:courier new,courier,monospace;">()avg.apply</span> على مُعامِل أوَّل فارغ null؟ يُمكننا إعادة النَّظر في ذلك الآن. المُعامِل الأول في <span style="font-family:courier new,courier,monospace;">()apply</span> هو الكائن الذي يجب أن يُعامَل على أنَّهُ 'this'. هذا تنفيذٌ تافه لـ new على سبيل المثال:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">function trivialNew(constructor, ...args) {
  var o = {}; // Create an object
  constructor.apply(o, args);
  return o;
}</pre><p>لا يُعتَبرُ هذا نُسخة طبق الأصل من new لأنها لم تقم بإعداد سلسلة النَّموذج (سيكون من الصَّعب التَّوضيح). هذا ليس شيئًا تستخدمه في كثيرٍ من الأحيان ولكن من المفيد أن تعرف عنه. يُطلَق على مُقتطف ...args (بما في ذلك علامات الحذف) "المُعامِلات المُتبقّية" <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/rest_parameters">rest arguments</a> - كما يُوحِي اسمها فهي تحتوي على بقيَّة المُعامِلات.</p><p>استدعاء</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">var bill = trivialNew(Person, "William", "Orange");</pre><p>يُعادِل تقريبًا</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">var bill = new Person("William", "Orange");</pre><p>لدى <span style="font-family:courier new,courier,monospace;">()apply</span> دالَّة أخت اسمها <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/call">call</a>، والتي أيضًا تُتيحُ لكَ تعيين this ولكنَّها تأخذ قائمة موسَّعة من المُعامِلات بدلًا من مصفوفة.</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">function lastNameCaps() {
  return this.last.toUpperCase();
}
var s = new Person("Simon", "Willison");
lastNameCaps.call(s);
// Is the same as:
s.lastNameCaps = lastNameCaps;
s.lastNameCaps();</pre><h3>الدوالّ الداخليّة</h3><p>تعريفات دالَّة JavaScript مسموحٌ بها داخل دوال أخُرى. لقد رأينا هذا من قبل مع دالَّة <span style="font-family:courier new,courier,monospace;">()makePerson</span>. هُناك تفصيل مهمّ في الدوال المُتداخلة في JavaScript وهو أنَّه يُمكِنُها الوصول إلى مُتغيِّرات في نِطَاق الدالَّة الأم:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">function betterExampleNeeded() {
  var a = 1;
  function oneMoreThanA() {
    return a + 1;
  }
  return oneMoreThanA();
}</pre><p>يوفِّر هذا قدرًا كبيرًا من الفائدة في كتابة تعليمات برمجيَّة أكثر صيانة. إذا اعتَمَدَتْ دالَّة على واحدة أو اثنتين من الدوال الأُخرى غير المُفيدة لأي جُزء من تعليماتك البرمجيَّة، يُمكنكَ إدخال تلك الدوال ذات المنفعة في الدالَّة التي سيتمّ استدعاؤها من مكان آخر. يُحافظ هذا على عدد من الدوال التي هي في النطاق العام، وهذا دائمًا شيءٌ جيد.</p><p>يُعتبر هذا عدَّاد كبيرة لإغراء المُتغيِّرات العامَّة global variables. عند كتابة تعليمات برمجيَّة معقَّدة غالبًا ما يكون مُغريًا استخدام مُتغيِّرات عامَّة لتبادُل القيم بين دوالّ مُتعدِّدة - الأمر الذي يؤدِّي إلى تعليمات برمجيِّة من الصعب صيانتها. يُمكنُ للدوالّ المُتداخلة مُشاركة المُتغيِّرات الموجودة في الدالَّة الأم، لذلك يُمكنكَ استخدام هذه الآليَّة لتجميع دالَّتين معًا متى كان هذا منطقيَّا دون تلويث مساحتُكَ العامَّة – ‘محليّات عامَّة’ إذا أردتَ أن تُطلِق عليها ذلك. ينبغي استخدام هذا الأسلوب مع الحذر، إلَّا أنَّ حوذته قُدرة مُفيدة.</p><h2>الإغلاق</h2><p>يقودنا هذا إلى واحدة من التجريدات الأكثر قوّة التي بإمكان Javascript تقديمها - ولكن أيضًا الأكثر تعريضًا للارتباك. ماذا تفعل هذه التعليمات البرمجيَّة؟</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">function makeAdder(a) {
  return function(b) {
    return a + b;
  };
}
var x = makeAdder(5);
var y = makeAdder(20);
x(6); // ?
y(7); // ?</pre><p>يجب أن يكون اسم دالَّة makeAdder قد أوضَح كل شيء: يقوم بخلق دوال 'adder' جديدة، تلك الدوال التي عند استدعائها بواسطة مُعامِل تقوم باضافته إلى المُعامِل الذي تم إنشائهم بواسطته.</p><p>ما يحدث هُنا هو إلى حدٍّ كبير نفس ما كان يحدث مع الدوال الداخليَّة في وقتٍ سابق: للدالَّة المُعرَّفة داخل دالَّة أخرى حقّ الوصول إلى مُتغيِّرات الدالَّة الخارجيَّة. الفرقُ الوحيدُ هُنا هو أن الدالَّة الخارجيَّة قد عادت، وبالتالي الحس السليم يهدي إلى أن مُتغيِّراتها المحليَّة لم تعد موجودة. لكنها لا تزال موجودة - لولاها دوال adder ما كانت قادرة على العمل. ما هو أكثر من ذلك، هناك نوعان من "نسخ" مختلفة من المُتغيِّرات المحليّة الخاصَّة بـ makeAdder - نُسخة بها a هو 5 ونُسخة بها a هو 20. وبُناءً على ذلك فإن نتيجة استدعاءَات الدالَّة تلك هي على النحو التالي:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">x(6); // returns 11
y(7); // returns 27</pre><p>إليكَ ما يحدُث فعليًّا. عندما تقوم Javascript بتنفيذ دالَّة يتمّ إنشاء كائن 'نطاق' للاحتفاظ بالمُتغيِّرات المحليَّة التي تم إنشاؤها داخل تلك الدالَّة. يتمّ تهيئتها مع أيّ مُتغيَّر يتمّ ارساله كعامِل دالَّة مُتغيِّر. يُشبه هذا الكائن العام الذي يحتوي على جميع المُتغيِّرات والدوال العامَّة، ولكن هُناك مع بعض الاختلافات الهامَّة: أوَّلُها، يتمَّ إنشاء كائن نطاق جديد تمامًا في كل مرة تبدأ دالَّة بالتنفيذ. ثانيها، لا يُمكن الوصول المُباشِر إلى كائنات النطاق تلك من خلال جُمل Javascript البرمجيَّة الخاصَّة بك، على عكس الكائن العام (الذي يُمكن الوصول إليه كـ this ويُمكن الوصول إليه في المُتصفِّحات كـwindow). على سبيل المثال ليس هُناك آليَّة لتكرار خصائص كائن النِطاق الحالي.</p><p>لذلك عندما يتم استدعاء makeAdder، يتمّ إنشاء كائن نطاق مع خاصيَّة واحدة: a، والذي هو المُعامِل الذي تمّ تمريره إلى دالَّة makeAdder. تُعيد بعد ذلك makeAdder دالَّة تمّ إنشاؤها حديثًا. في هذه المرحلة عادةً يقوم جامع القُمامة في JavaScript بتنظيف كائن النطاق الذي تمّ خلقه لـ makeAdder، ولكن الدالًّة المُعادة تُحافظ على مرجع إلى كائن النطاق هذا. نتيجة لذلك، لن يكون كائن النطاق القمامة مُجمَّعة إلى أن لا يكون هُناك أيَّة مراجع إلى كائن الدالَّة التي أعادتها makeAdder.</p><p>تُكوِّن كائنات النطاق سلسلة تُسمَّى سلسلة نطاق scope chain، على غرار سلسلة النَّموذج المُستخدمة من قبل نظام كائن JavaScript.</p><p>الإغلاق هو مزيجٌ من دالَّة وكائن النِّطاق الذي بِهِ تمّ إنشاء تلك الدالَّة.</p><p>يُمكِّنُكَ الإغلاق من حفظ الحالة - كما أنَّه كثيرًا ما يمكن استخدامه بدلًا من الكائنات. يُمكِن العثور على عدَّة مُقدِّمات ممتازة للإغلاق <a rel="external nofollow" href="http://stackoverflow.com/questions/111102/how-do-javascript-closures-work">هُنا</a>.</p><h3>تسريبات الذَّاكرة</h3><p>أحد الآثار الجانبيّة المؤسفة للإغلاق هو أنَّه يجعل من السَّهل تسرب الذاكرة في Internet Explorer. Javascript هي لغة تجميع البيانات المُهملة - تُخصَّص ذاكرة للكائنات عند إنشائها ويتم استعادة تلك الذَّاكرة من قِبَل المُتصفِّح عندما لا تتبقَّى مراجع إلى كائن. يتم التعامل مع الكائنات التي توفّرها البيئة المضيفة عن طريق تلك البيئة.</p><p>تحتاج مُستضيفات المُتصفِّح إلى إدارة عدد كبير من الكائنات التي تمثل صفحة HTML المُقدَّمة ألا وهي كائنات الـ DOM. الأمر متروك للمُتصفِّح لإدارة تخصيص واسترداد هذه الكائنات.</p><p>يستخدم Internet Explorer لهذا آلية جمع القمامة الخاصَّة به، بعيدًا عن الآليَّة المستخدمة لـ JavaScript. إنَّ التفاعل بين الآليَّتين هو ما قد يتسبِّب في تسرُّب الذَّاكرة.</p><p>يحدث تسرُّب الذاكرة في IE أي وقت يتمّ تشكيل مرجع دائري بين كائن JavaScript وكائن أصلي. تأمَّل ما يلي:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">function leakMemory() {
  var el = document.getElementById('el');
  var o = { 'el': el };
  el.o = o;
}</pre><p>تخلُق المراجع الدائريَّة المُشكَّلة بالأعلى تسرُّب للذَّاكرة. لن يقوم IE بتحرير الذَّاكرة المُستخدمة من قِبَل el وo حتَّى يتمّ إعادة تشغيل المُتصفِّح تمامًا.</p><p>من المُرجَّح ألّا تُلاحَظ الحالة المذكورة أعلاه. يُصبح تسرُّب الذَّاكرة مصدر قلق حقيقي فقط في التطبيقات طويلة التشغيل أو التطبيقات التي تُسرِّب قدرًا كبيرًا من الذَّاكرة بسبب هياكل البيانات الكبيرة أو أنماط التسرُّب داخل الحلقات.</p><p>نادرًا ما تكون التسريبات واضحة بهذا الشَّكل - في كثيرٍ من الأحيان يمكن أن يكون لهيكل البيانات المسرَّبة عدة طبقات من المراجع تقومُ بالعتيم على مرجع مُعاد.</p><p>يجعلُ الإغلاق من السَّهل خلق تسرُّب ذاكرة دون قصد. انظر إلى التعليمات البرمجيَّة هذه:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">function addHandler() {
  var el = document.getElementById('el');
  el.onclick = function() {
    el.style.backgroundColor = 'red';
  };
}</pre><p>تقوم التعليمات البرمجيَّة أعلاه بتحويل العنصر إلى أحمر عند النقر عليه. كما أنَّها أيضًا تخلُق تسرُّب ذاكرة. لماذا؟ لأن الإشارة إلى el قُبِضَت دون قصد في الإغلاق الذي تمَّ إنشاؤه للدالَّة الداخليَّة المجهولة. يخلُق هذا مرجعًا دائريًّا بين كائن JavaScript (الدالَّة) وكائن أصلي (el).</p><p>هُناك عدد من الحلول لهذه المشكلة. أبسطُها هو عدم استخدام مٌتغيِّر el:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">function addHandler(){
  document.getElementById('el').onclick = function(){
    this.style.backgroundColor = 'red';
  };
}</pre><p>المُثير للدَّهشة أن هُناك خدعة لكسر المراجعِ الدائريَّة تُقدَّم بواسطة الإغلاق، هذه الخُدعة هي إضافةُ إغلاقٍ آخر:</p><pre data-pbcklang="javascript" data-pbcktabsize="" class="javascript ipsCode prettyprint">function addHandler() {
  var clickHandler = function() {
    this.style.backgroundColor = 'red';
  };
  (function() {
    var el = document.getElementById('el');
    el.onclick = clickHandler;
  })();
}</pre><p>يتمُّ تنفيذ الدالّة الداخليّة على الفور وتُخفي محتوياتها عن الإغلاق الذي تمَّ انشاؤه باستخدام clickHandler.</p><p>خدعة أُخرى جيّدة لتجنب الإغلاق هي كسر المراجعِ الدائريَّة خلال حدث window.onunload. سوف تقوم العديد من مكتبات الحدث بتنفيذِ ذلك بدلًا عنك. لاحظ عمل بذلك يقوم بتعطيل <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Working_with_BFCache">ذاكرة التخزين المؤقت back-forward في فيرفُكس</a>، لذلك يجبُ عليكَ أن لا تُسجِّل مُستمع unload في فَيرفُكس، إلا إذا كان لديك أسباب أخرى للقيام بذلك.</p>
]]></description><guid isPermaLink="false">92</guid><pubDate>Tue, 02 Jun 2015 20:09:00 +0000</pubDate></item><item><title>&#x623;&#x646;&#x645;&#x627;&#x637; &#x627;&#x644;&#x62A;&#x635;&#x645;&#x64A;&#x645; &#x641;&#x64A; JavaScript: &#x646;&#x645;&#x637; &#x627;&#x644;&#x645;&#x64F;&#x634;&#x64A;&#x651;&#x650;&#x62F; (Constructor)</title><link>https://academy.hsoub.com/programming/javascript/%D8%A3%D9%86%D9%85%D8%A7%D8%B7-%D8%A7%D9%84%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%81%D9%8A-javascript-%D9%86%D9%85%D8%B7-%D8%A7%D9%84%D9%85%D9%8F%D8%B4%D9%8A%D9%91%D9%90%D8%AF-constructor-r48/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_03/js-design-patterns_480x300.png.baf6c708de8fb1370d27dbfb1c521ecd.png" /></p>
<p><em>في سلسلة من عدة أجزاء سنناقش موضوعًا نظريًّا يُعتبر من أساسيّات هندسة البرامج، وهو أنماط التصميم (Design Patterns)، وسنعتمد لغة JavaScript في نقاشنا لتصاعد شعبيّتها ومرونتها التي تسمح لنا ببناء مشاريعنا وفق أنماط متنوّعة مما سيُسهّل علينا شرح موضوع السّلسلة</em></p><h2>نمط المُشيِّد (Constructor)</h2><p>يشيع استخدام المُشيّدات في اللغات الكائنيّة التّوجّه، حيث تُستخدم لإنشاء نُسخ (instances) من الأصناف (classes)، ومع أنّ JavaScript ليست لغةً كائنيّة التّوجّه بالمعنى التّقليديّ، إلّا أنّها تسمح بإنشاء نُسخ عن كائنات باستخدام بالمُشيّدات، ويمكن لأيّ دالّة أن تُستخدم كمُشيّد، وذلك بأن نُسبقها بالكلمة <code>new</code>، ولتوضيح هذا النّمط سنقوم بإنشاء مُنبّه (كالّذي تضبطه للاستيقاظ في هاتفك) يمكن ضبطه إلى تاريخ ووقت معيّنين ثمّ تفعيله أو تعطيله حسب الرّغبة:</p><pre class="javascript ipsCode prettyprint">function Alarm(when) {
    this.setAt = when;
    this.enable = function() {
        var startAfter = new Date(this.setAt) - new Date;
        console.log("Alarm will wake you up after " + startAfter/1000 + " seconds");
        this.timeout = setTimeout(function() {
            console.log("Wake up!");
        }, startAfter);
    }
    this.disable = function() {
        if (this.timeout) {
            clearTimeout(this.timeout);
            delete this.timeout;
            console.log("Alarm diabled");
        }
    }
}

var a = new Alarm("2015-03-19 5:58 PM");
a.enable()
// Alarm will wake you up after 8.982 seconds

// After a few seconds:
// Wake up!</pre><p>في المثال السّابق نُسمّي الدّالة <code>Alarm()‎</code> مُشيّدًا (constructor)، والكائن <code>a</code> نُسخة (instance).</p><p>لاحظ أنّ <code>Alarm</code> في المثال السّابق ليست سوى دالّة (function)، فهي ليست صنفًا كما في لغات أخرى مثل Java وC++، إذ تُعتبر الدّوال في JavaScript مكوّنًا من الدّرجة الأولى وتُعامل كما يُعامل أيّ كائن، وهكذا يمكن استخدامها كمشيّد لكائن آخر ممّا يسمح بمحاكاة مفهوم الأصناف الّذي لم يُضَف إلّا مؤخّرًا في JavaScript. من عيوب المِثال السّابق إسناد الدّوال الّتي ستعمل عمل الوظائف (methods) إلى النُسخة ذاتها عند إنشائها، وهذا يعني تكرار محتوى الدّوال في الذّاكرة مع كلّ نسخة جديدة من الكائن <code>Alarm</code>، بينما يمكننا توفير هذا الاستهلاك غير المُبرّر للذّاكرة بإسناد الدّوال إلى النّموذج البدئيّ للكائن (أي إلى <code>Alarm.prototype</code>) مما يسمح بمشاركتها بين كل نسخ الكائن، لتقوم الآلة الافتراضيّة بتنفيذ النّصّ البرمجيّ للدّالّة ذاتها بسياق النّسخة (instance context) الّتي استدعت الدّالة، أي إنّ <code>this</code> تُشير ضمن الدّالة عند تنفيذها إلى النُسخةَ المنشأة وليس الصّنف؛ بالطّبع ليس من المرغوب تطبيق الفكرة ذاتها على المُتغيّرات الأخرى مثل <code>setAt</code>، لأنّه من البديهيّ أن تختلف قيمتها بين نسخة وأخرى. لنُعد كتابة المثال السّابق بصورة أفضل:</p><pre class="javascript ipsCode prettyprint">function Alarm(when) {
    this.setAt = when;
}

Alarm.prototype.enable = function() {
    var startAfter = new Date(this.setAt) - new Date;
    console.log("Alarm will wake you up after " + startAfter/1000 + " seconds");
    this.timeout = setTimeout(function() {
            console.log("Wake up!");
    }, startAfter);
}

Alarm.prototype.disable = function() {
    if (this.timeout) {
        clearTimeout(this.timeout);
        delete this.timeout;
        console.log("Alarm diabled");
    }
}
var a = new Alarm("2015-03-19 6:21 PM");
a.enable();
//  Alarm will wake you up after 30.243 seconds

// After 30 seconds...
// Wake up!</pre><p>هذا الأسلوب في إنشاء الأصناف شائع جدًّا، وهو يتطلّب فهمًا دقيقًا لآليّة الوراثة في JavaScript؛ إذ يُبنى كلّ كائنٍ فيها على كائن آخر يُسمّى النّموذج البدئيّ (prototype)، ويقوم هذا الكائن الأخير على كائن ثالث أعلى منه في السّلسلة هو نموذجه البدئيّ، وهكذا حتّى نصل إلى <code>null</code> الّذي ليس له نموذج بدئيّ بحسب تعريف اللّغة. في مثالنا السّابق الكائن <code>Alarm.prototype</code> هو النّموذج البدئيّ للكائن <code>a</code>، وهذا يعني أنّ كل الخواصّ المُسندة إلى <code>Alarm.prototype</code> وما فوقه ستكون مُتاحة للكائن <code>a</code>، ولو كتابنا برنامجًا مُشابهًا بـJava لقُلنا إنّ <code>Alarm</code> صنفٌ وإنّ <code>a</code> نُسخة عن هذا الصّنف (instance). عندما نحاول الوصول إلى الخاصّة <code>a.setAt</code>، فإنّ مُفسِّر JavaScript يبدأ بالبحث عن هذه الخاصّة من أدنى سلسلة الوراثة، أي من الكائن <code>a</code> ذاته، فإنّ وجدها قرأها وأعاد قيمتها، وإلّا تابع البحث صعودًا إلى النّموذج البدئيّ وهكذا... وطبيعة JavaScript هذه هي ما سمح لنا بإسناد الوظيفتين <code>enable</code> و<code>disable</code> إلى <code>Alarm.prototype</code> مطمئنّين إلى أنّها ستكون مُتاحة عند قراءة <code>a.enable()‎</code> و<code>a.disable()‎</code>. يمكن التأكّد من النّموذج البدئيّ للكائن <code>a</code> كما يلي:</p><pre class="javascript ipsCode prettyprint">Object.getPrototypeOf(a) == Alarm.prototype;
// true</pre><h3>الأصناف في ECMAScript 6</h3><p>يُقدّم الإصدار الأحدث من JavaScript مفهوم الأصناف (classes) بصورته التّقليديّة المعروفة في اللّغات الأخرى، إلّا أنّه ليس سوى أسلوب آخر لصياغة النّماذج البدئيّة (أو ما يُسمّى syntactic sugar)، وهذا يعني أنّه نموذج الوراثة في JavaScript لم يتغيّر. يمكننا إعادة كتابة المثال السّابق بصياغة الأصناف في ES6 كما يلي:</p><pre class="javascript ipsCode prettyprint">class Alarm {
    constructor(when) {
        this.startAt = when;
    }

    enable() {
        var startAfter = new Date(this.setAt) - new Date;
        console.log("Alarm will wake you up after " + startAfter/1000 + " seconds");
        this.timeout = setTimeout(function() {
            console.log("Wake up!");
        }, startAfter);
    }

    disable() {
        if (this.timeout) {
            clearTimeout(this.timeout);
            delete this.timeout;
            console.log("Alarm diabled");
        }
    }
}</pre><p>وستُسند الدّوال <code>enable()‎</code> و<code>disable()‎</code> إلى <code>Alarm.prototype</code> تمامًا كما في المثال الذي سبقه.</p><p>يُذكر أنّ استخدام <code>new</code> ليست الطّريقة الوحيدة لتشييد الكائنات، إذ يمكن استخدام الوظيفة <code>Object.create()‎</code> لتُعطي النّتيجة ذاتها:</p><pre class="javascript ipsCode prettyprint">var a = Object.create(Alarm.prototype);

Object.getPrototypeOf(a) == Alarm.prototype;
// true</pre><h3>إسناد الخواصّ إلى الكائنات</h3><p>‏JavaScript لغة ديناميكية، وهذا يعني أنّه يمكن إضافة وحذف الخواصّ من الكائنات وتعديل نماذجها البدئيّة أثناء التّنفيذ، وهذا ما يمنحها القسم الأكبر من مرونتها ويجعلها مناسبة للاستخدام في بيئة مُعقّدة مثل بيئة الويب، وليس من الغرابة أن توفّر اللّغة وسائل متعدّدة لإسناد الخصائص إلى الكائنات لتلبية الحاجات المتنوّعة لتطبيقات الويب.</p><p>ماذا لو أردنا تغيير قيمة المنبّه في مثالنا السّابق بعد تفعيله؟ لربّما ترادونا للوهلة الأولى إمكانيّة تغيير قيمة الخاصّة <code>setAt</code> بالطّريقة التّقليدية:</p><pre class="javascript ipsCode prettyprint">a.setAt = "2016-03-03 03:03 PM";
// or
a["setAt"] = "2016-03-03 03:03 PM";</pre><p>لكنّ نتيجة هذا الفعل لن تكون كما يُتوقّع، فلو عدنا للمثال السابق وتمعّنا في خواصّه، للاحظنا عيبًا في كيفيّة عمل المُنبّه، إذ إنّ الخاصّة <code>setAt</code> مكشوفة ويمكن تغيير قيمتها في أيّ وقت، حتى بعد تفعيل المُنبّه، إلّا أنّ تغييرها بعدئذٍ لن يغيّر اللّحظة الحقيقيّة الّتي سينطلق فيها المنبّه كما يتضّح لنا عند قراءة النّصّ البرمجيّ، ولذا فنحن هنا أمام حلّين: إمّا منع تغيير قيمة الخاصّة <code>setAt</code> وجعلها للقراءة فقط بعد إنشاء المُنبّه، أو إيقاف المنبّه وإعادة ضبطه في كلّ مرّة تُغيّر فيها قيمة الخاصّة <code>setAt</code>، وكلا الحلّين متاحان إذا كنّا على علم بأساليب إسناد الخصائص في JavaScript.</p><p>توفّر اللّغة الوظيفة <a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/defineProperty"><code>Object.defineProperty()‎</code>‏</a> الّتي تسمح بتعريف خواصّ لكائن ما مع إمكانيّة التّحكم بتفاصيل هذه الخاصّة، ومن هذه التّفاصيل:</p><ul><li>هل الخاصّة قابلة للكتابة؟ (<code>writable</code>)</li><li>هل يجب المرور على هذه الخاصّة عند سرد خواصّ الكائن؟ (<code>enumerable</code>)</li><li>ما الذي يحدث عند إسناد قيمة للخاصّة؟ (<code>set</code>)</li><li>ما الذي يحدث عند قراءة قيمة الخاصّة؟ (<code>get</code>)</li></ul><p>وبهذا يمكننا بسهولة منع تغيير قيمة الخاصّة <code>setAt</code> بعد إسنادها:</p><pre class="javascript ipsCode prettyprint">function Alarm(when) {
    Object.defineProperty(this, "setAt", { 
        value: when,
        writable: false
    })
}

Alarm.prototype.enable = function() {
    var startAfter = new Date(this.setAt) - new Date;
    console.log("Alarm will wake you up after " + startAfter/1000 + " seconds");
    this.timeout = setTimeout(function() {
            console.log("Wake up!");
    }, startAfter);
}
Alarm.prototype.disable = function() {
    if (this.timeout) {
        clearTimeout(this.timeout);
        delete this.timeout;
        console.log("Alarm diabled");
    }
}
var a = new Alarm("2015-03-19 7:51 PM");
a.setAt = new Date("2016-03-19");

console.log(a.setAt);

// "2015-03-19 7:51 PM"</pre><p>لاحظ أنّ قيمة <code>setAt</code> لم تتغيّر. هذا حلّ جيّد، لكن سيكون من الأفضل السّماح للمُستخدم بتعديل قيمة المنبّه، وعندها سنلجأ لإيقاف المنّبه وإعادة ضبطه كما يلي:</p><pre class="javascript ipsCode prettyprint">function Alarm(when) {
    var _hidden_value = new Date(when);
    Object.defineProperty(this, "setAt", { 
        set: function(newValue) {
            _hidden_value = new Date(newValue);
            if (this.timeout) {
                this.disable();
                console.log("Alarm changed to " + newValue);
                console.log("You need to re-enable the alarm for changes to take effect");
            }
        },
        get: function() {
            return _hidden_value;
        }
    })
}

Alarm.prototype.enable = function() {
    var startAfter = new Date(this.setAt) - new Date;
    console.log("Alarm will wake you up after " + startAfter/1000 + " seconds");
    this.timeout = setTimeout(function() {
            console.log("Wake up!");
    }, startAfter);
}

Alarm.prototype.disable = function() {
    if (this.timeout) {
        clearTimeout(this.timeout);
        delete this.timeout;
        console.log("Alarm diabled");
    }
}

var a = new Alarm("2016-03-03 03:03 PM")
a.enable();
// Alarm will wake you up after 30221933.66 seconds

a.setAt = "2015-03-19 8:05 PM";
// Alarm changed to 2015-03-19 8:05 PM
// You need to re-enable the alarm for changes to take effect

a.enable()
// Alarm will wake you up after 20.225 seconds

// After 20 seconds...
// Wake up!</pre><p>لاحظ أنّنا سنحتاج إلى مُتغيّر سرِّيِّ (<code>‎_hidden_value</code>) نُخزّن فيه القيمة الفعليّة لوقت التّنبيه.</p><h2>متى أستخدم هذا النّمط؟</h2><p>نمط المُشيّد لا يحتكر بنية مشروعك عند استخدامه؛ معنى هذا أنّه لا شيء يمنعك من استخدام نمط المُشيّد مع أي نمط آخر عند الحاجة لذلك، فيمكن (بل يشيع كثيرًا) استخدام المُشيّدات ضمن الوحدات (modules) ثمّ تصديرها لاستخدامها من موضع آخر في المشروع، ومثال ذلك أشياء مثل <a rel="external nofollow" href="https://nodejs.org/api/events.html#events_class_events_eventemitter"><code>EventEmitter</code>‏</a> و<a rel="external nofollow" href="https://nodejs.org/api/stream.html">Streams‏</a> في Node.js. كما يمكن بناء أنماط أخرى سنتعرّف عليها لاحقًا على أساس المُشيِّدات مثل نمط الكائن المُتفرّد (Singleton) ونمط المُراقِب (Observer pattern).</p><p>المصادر:</p><ol><li><a rel="external nofollow" href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Inheritance_and_the_prototype_chain">شبكة مُطوّري موزيلّا: Inheritance and the prototype chain‏</a></li><li>كتاب <em><a rel="external nofollow" href="http://addyosmani.com/resources/essentialjsdesignpatterns/book/">JavaScript Design Patterns‏</a></em> لمؤلّفه Addy Osmani</li></ol>]]></description><guid isPermaLink="false">48</guid><pubDate>Mon, 23 Mar 2015 09:29:00 +0000</pubDate></item><item><title>&#x623;&#x646;&#x645;&#x627;&#x637; &#x627;&#x644;&#x62A;&#x635;&#x645;&#x64A;&#x645; &#x641;&#x64A; JavaScript: &#x627;&#x644;&#x648;&#x62D;&#x62F;&#x627;&#x62A;</title><link>https://academy.hsoub.com/programming/javascript/%D8%A3%D9%86%D9%85%D8%A7%D8%B7-%D8%A7%D9%84%D8%AA%D8%B5%D9%85%D9%8A%D9%85-%D9%81%D9%8A-javascript-%D8%A7%D9%84%D9%88%D8%AD%D8%AF%D8%A7%D8%AA-r47/</link><description><![CDATA[
<p><img src="https://academy.hsoub.com/uploads/monthly_2015_03/js-design-patterns_480x300.png.c38d9848f4dd7ae012859436dcbfdfc8.png" /></p>
<p><em>في <a href="http://academy.hsoub.com/search/?tags=javascript+design+patterns">سلسلة من عدة أجزاء</a> سنناقش موضوعًا نظريًّا يُعتبر من أساسيّات هندسة البرامج، وهو أنماط التصميم (Design Patterns)، وسنعتمد لغة JavaScript في نقاشنا لتصاعد شعبيّتها ومرونتها التي تسمح لنا ببناء مشاريعنا وفق أنماط متنوّعة مما سيُسهّل علينا شرح موضوع السّلسلة</em></p><h2>ما هي أنماط التصميم؟</h2><p>عندما تبدأ بتعلّم البرمجة، فغالبًا ما يكون اهتمامك مُنصبًّا على أن يكون البرنامج قادرًا على إنجاز المهمّة الّتي تريدها قبل كل شيء، أمّا بعد أن تتطوّر مهاراتك، فسينتقل اهتمامك إلى مواضيع أكثر عمقًا، وستبدأ بطرح بعض الأسئلة على نفسك، حتّى قبل أن تبدأ بكتابة البرنامج، من هذه الأسئلة:</p><ul><li>كيف أبني برنامجي بحيث يسهُل تحسينه فيما بعد؟</li><li>كيف أتأكّد أن برنامجي سيبقى يؤدّي ما يُتوقّع منه حتّى وإن قمت بتعديل أجزاء منه بعد زيادة تعقيده؟</li><li>كيف أبني برنامجي بحيث أستطيع إعادة استخدام أجزاء منه في برامج أخرى في المستقبل؟</li><li>كيف أجعل برنامجي يستخدم أجزاء من مشاريع أخرى كتبها مطوّرون آخرون؟</li></ul><p>الإجابة على هذه الأسئلة هي واحدة دومًا: اختر نمط التصميم المناسب لمشروعك.</p><p>لم نُعرِّف بعدُ مفهوم نمط التّصميم، لكنّنا بدأنا نُكوّن فكرة عنه. نمط التّصميم هو وصف لطريقة مُعيّنة في حلّ مشكلة برمجيّة ما، فالعديد من المُشكلات البرمجيّة يمكن حلّها بأكثر من طريقة، ولكلّ طريقة مساوئ ومحاسن، وبعضها قد يكون أكثر مُناسبةً للمشروع الحاليّ، واختيار نمط التصميم المُناسب سيضمن استمرار تطوّر المشروع بسهولة وربّما يُفيدنا في عزل أجزاء منه لإعادة استخدامها في مشاريع أخرى بحيث لا نُضطَّر لكتابتها مرارًا.</p><p>أغلب الظنّ أنّك تستخدم واحدًا أو أكثر من أنماط التّصميم وإن لم تعرف ما هي أنماط التّصميم بمعناها النّظريّ، فإنشاء أصناف (classes) لمفاهيم مُجرّدة في اللّغات الكائنيّة التّوجّه (object-oriented) وإنشاء نُسخ عنها (instances) وتوزيع هذه الأصناف في ملفّات مستقلّة، هو في الواقع نمط من أنماط التّصميم.</p><p>يُرجى الانتباه إلى أن التّطبيق العمليّ لأنماط التّصميم يفرض على المطوّر دمج أكثر من نمط معًا وشرحنا لأحدها لا يمكن أن يخلو من استخدام لأنماط أخرى كما سيتبيّن لك بعد انتهاء السّلسلة، إذ يمكن مثلًا إنشاء وحدة (module) تُصدِّر صنفًا (class) وهذا يعني أنّنا استخدمنا نمطين اثنين (نمط الوحدات، ونمط مُشيّد الكائنات constructor) في وقت واحد.</p><h2>نمط الوحدات (Module Pattern)</h2><p>بغرض تبسيط الأمور، سنبدأ بتوضيح أحد أنماط التّصميم الشّائعة في JavaScript، وهو ما يُعرف بنمط الوحدات (module pattern)، والتي ازدادت شعبيّة بعد ظهور Node.js وما أحدثته من تأثير انتقل حتّى إلى أساليب بناء وتصميم المكتبات البرمجيّة الّتي تستهدف المُتصفّحات.</p><p>الوحدات هي أجزاء مُستقلّة ومعزولة من النّص البرمجيّ للمشروع توفّر مهمّة مُعيّنة، الأمر الّذي يجعل الهدف من كل وحدة واضحًا ومحدّدًا ويُجنّب المشروع الفوضى التي تنتج عن كتابة كامل النّصّ البرمجيّ في كتلة واحدة متداخلة يصعب معها تنقيحه وصيانته.</p><p>فصل الأجزاء هذا ليس الفائدة الوحيدة الّتي يُقدّمها نمط الوحدات، إذ من خلاله يمكن مُحاكاة مفهوم المكوّنات السّرّيّة (private) والعلنيّة (public) وحماية بعض محتويات الوحدة من الوصول إليها من خارجها في JavaScript، وذلك بإخفائها ضمن الوحدة والامتناع عن تصديرها الأمر الذي يجعل الوصول إليها من خارج الوحدة مستحيلًا كما سنوضّح بعد قليل.</p><p>تتوفّر في عالم JavaScript أشكال مختلفة لتصميم الوحدات، منها:</p><ul><li>الكائنات الحرفيّة (object literals)</li><li>الدّوالّ المغلقة المجهولة (anonymous closures)</li><li>وحدات CommonJS</li><li>وحدات AMD</li><li>وحدات ECMAScript 6</li></ul><p>الشّكل الأول ربّما هو أبسط الأشكال وأكثرها بدائيّة، وهو يعني ببساطة إنشاء كائن باستخدام صياغة القوسين المعكوفين <code>{}</code> يضمّ خصائص ووظائف متعلّقة بمهمّة واحدة لعزلها وتسهيل استخدامها:</p><pre class="javascript ipsCode prettyprint">var userSettings = {
    preferences: {
        privacy: "strict",
        language: "ar",
        showEmail: false,
        available: true,
    },
    updatePreferences: function(newPrefs) {
        this.preferences = newPrefs;
    }
}</pre><p>بعض خبراء JavaScript لا يعتبرون هذا النّمط وحدةً حقيقيّة لبساطته الشّديدة، فمن الواضح أنّ هذا النّمط أبسط من حاجات التّطبيقات المعقّدة، فغالبًا ما يكون توزيع الوحدات على ملفّات منفصلة أمرًا مرغوبًا أثناء تطوير التّطبيقات ولهذا نحتاج إلى وسيلة لاستيراد هذه الملفّات وتصديرها بما يسمح باستخدام وحدة واقعة في ملفّ من ملفّ آخر، ولهذا الغرض طوّر مجتمع JavaScript خلال الأعوام الماضية أساليب قياسيّة اتّفق على استخدامها على الرّغم من أن اللّغة ذاتها لم تقدّم مفهوم الوحدات إلّا في الإصدار الأخير (ES6)، والذي استلهم من الأساليب السّابقة أصلًا؛ كما أنّنا قد نرغب بحماية كائن مثل <code>preferences</code> في مثالنا السّابق من تعديله بصورة مباشرة.</p><p>الشّكل الثّاني هو أسلوب أكثر تطوّرًا لإنشاء الوحدات، ويحتاج فهمه إلى فهم معنى الدّوال المُغلقة (closures)، فإذا كانت لدينا دالّة تُعيد عند استدعائها دالّة أخرى، فإنّنا ندعو الدّالة الأخيرة دالّة مُغلقة، ويتاح لهذه الدّالة الوصول إلى المتّغيّرات الّتي كانت مفروضة في الدّالة الأولى حتّى عندما تُستدعى من خارجها:</p><pre class="javascript ipsCode prettyprint">function addNumberToN(n) {
    return function(number) {
        return n + number;
    }
}
var addTo2 = addNumberToN(2);
var five = addTo2(3); // 5</pre><p>هذه الخاصيّة في JavaScript تسمح لنا بعزل المتّغيّرات (encapsulation) ضمن الدّالة الخارجيّة مع الاحتفاظ بإمكانيّة الوصول إليها من الدّوال والكائنات الفرعيّة، الأمر الذي يحاكي مفهوم خصوصيّة المتغيّرات في لغات البرمجة الأخرى (access modifiers).</p><p>لنفترض مثلًا أنّنا نريد أن نقوم بإنشاء عدّاد لعدد النّقرات على زرّ معيّن في تطبيقنا، ولا نريد الاحتفاظ بهذه القيمة في النّطاق العامّ لأنّ هذا قد يعرّضها للتّعارض من أسماء مُتغيّرات أخرى أو يجعلها قابلة للتّعديل من إضافات خارجيّة في المتصفّح، لهذا نقوم بإنشاء دالّة مُغلقة تُحيط بهذه القيمة:</p><pre class="javascript ipsCode prettyprint">function() {
    var counter = 0;
    return {
        increaseCounter: function() {
            counter++;
        }
    }
}</pre><p>وبهذا نكون قد قيّدنا إمكانيّة تعديل قيمة المتغيّر بزيادته فقط، وعبر الدّالة <code>increaseCounter()‎</code> فقط. لا يمكن استخدام الدّالّة <code>increaseCounter()‎</code> إلا بعد استدعاء الدّالة المجهولة (anonymous) الّتي تُحيط بها، ويتمّ هذا كما يلي:</p><pre class="javascript ipsCode prettyprint">(function() {
    var counter = 0;
    return {
        increaseCounter: function() {
            counter++;
        }
    }
})()</pre><p>لتُصبح الدّالة <code>increaseCounter()‎</code> مُتاحة في النّطاق العامّ، وبهذا نكون حصلنا على شكل بدائي لفكرة "تصدير الوحدات" (module exports).</p><p>لنستعرض الآن الأساليب الأخرى لإنشاء الوحدات، ولعلّ أكثر هذه الأساليب شيوعًا <a rel="external nofollow" href="http://wiki.commonjs.org/wiki/Modules">أسلوب CommonJS‏</a> المُعتمد في <a rel="external nofollow" href="http://nodejs.org/api/modules.html">Node.js‏</a>، والذي يُتيح استيراد الوحدات باستخدام الدّالّة <code>require()‎</code>:</p><pre class="javascript ipsCode prettyprint">var UrlMaker = require("./url-maker");
var url_maker = new UrlMaker("Hello World!");
var url = url_maker.make();
console.log(url); // hello-world;</pre><p>وأمّا تصدير الوحدات لإتاحة استخدامها، فيتم بإسناد الخصائص إلى الكائن <code>module.exports</code>، كما في الملفّ <code>url-maker.js</code> الموجود في مسار العمل الحالي:</p><pre class="javascript ipsCode prettyprint">module.exports = function UrlMaker(string) {
    return {
        make: function() {
            return string.toLowerCase().replace(/\s+/gi, "-").replace(/[!?*%$#@`]/gi, "")
        }
    }
}</pre><p>لا يقتصر استخدام أسلوب CommonJS على بيئة Node.js، بل يمكن نقله إلى المتصفّحات باستخدام برامج مثل <a rel="external nofollow" href="http://browserify.org">Browserify‏</a>.</p><p>من الأساليب الشائعة لإنشاء الوحدات كذلك نمط وحدات AMD (اختصارًا لـAsynchronous Module Definition) ولعلّه يُستخدم بكثرة مع مكتبة <a rel="external nofollow" href="http://requirejs.org">require.js‏</a> في المتصفّحات والّتي تسمح بتحميل الوحدات (الموزّعة كلّ منها على ملفّ منفصل) عند الحاجة إليها، إذ يتمّ التّصريح عن كلّ وحدة وما تعتمد عليه من وحدات أخرى وتقوم require.js بتلبية هذه المتطلبات بتحميل ملفّات الوحدات المنفصلة. في المثال التّالي، نُصرّح عن حاجة موقعنا لمكتبتي jQuery وUnderscore ووحدة أخرى قمنا بإنشائها بأنفسنا:</p><pre class="javascript ipsCode prettyprint">require(["jquery", "underscore", "user_profile"], function($, _, UserProfile) {
    var user = new UserProfile();
    user.firstName = $("#form input[name='first']").text();
    user.lastName = $("#form input[name='last']").text();
    user.username = $("#form input[name='username']").text();
    // ...
})</pre><p>ويتمّ التّصريح عن الوحدة <code>user_profile</code> في ملفّ منفصل باسم موافق:</p><pre class="javascript ipsCode prettyprint">define(function() {
    function Profile() {
        /* ... */
    }
    return Profile;
})</pre><p>يوفّر الإصدار الجديد من JavaScript‏ (ES6) دعمًا أساسيًّا لتعريف الوحدات واستيرادها وتصديرها، وسنتطرّق له بالتّفصيل في الجزء القادم من <a href="http://academy.hsoub.com/code/javascript">سلسلة التّعريف بميزات ES6 الجديدة</a>، لكنّ لا بأس من أن نتعرّف عليه سريعًا:</p><pre class="javascript ipsCode prettyprint">import { jQuery as $ } from "/jquery.js";
import { Profile as UserProfile } from "/user.js";

var user = new UserProfile();

user.firstName = $("#form input[name='first']").text();
// ...</pre><p>وتُنشئ الوحدة وتُصدَّر في الملفّ <code>user.js</code>:</p><pre class="javascript ipsCode prettyprint">class Profile {
    constructor() {
        // ...
    }
    validate() {
        // ...
    }
}
export { Profile };</pre><h2>فوائد استخدام الوحدات</h2><p>لنُلخِّص إذن فوائد الوحدات:</p><ul><li><strong>تنظيم النّصّ البرمجيّ</strong> للمشاريع الضّخمة بحيث يسهل فهم بنية البرنامج وتنقيحه ومتابعة صيانته في المستقبل.</li><li><strong>إدارة المُتطلّبات (dependencies):</strong> توضيح العلاقة بين مكوّنات المشروع، بحيث نستطيع إدارة ما تتطلّبه كلّ وحدة وتحميل هذه المتطلّبات آليًّا بالتّرتيب الصّحيح بدل الحاجة إلى التّصريح عن روابط المكتبات الخارجيّة في الصّفحة الرئيسيّة للموقع وإعادة ترتيبها كلّ ما تطلّب الأمر إضافة مكتبة جديدة تعتمد على أخرى.</li><li><strong>العزل (encapsulation):</strong> حماية أجزاء من المشروع من العبث بها سهوًا أو من نصوص برمجيّة خارجيّة، وذلك بعزلها ضمن نطاق فرعيّ خلافًا لتركها في النّطاق العامّ. ففي الحالة الطّبيعيّة تكون متغّيرات JavaScript المفروضة في النّطاق العامّ مُتاحة لأي دالّة، وأما عند فرض هذه المُتغيّرات ضمن الوحدات، فإنّ الوصول إليها يُصبح محدودًا بما هو داخل الوحدة ذاتها، ويتمّ ذلك باستغلال مفهوم النّطاقات (scopes) في JavaScript وإحاطة هذه المتغيّرات بدالّة تُغلّفها بنطاق فرعيّ ثمّ إعادة كائن يحوي فقط الخصائص الّتي نريد إتاحتها للعموم.</li></ul><h2>متى أستخدم هذا النّمط؟</h2><p>يُنصح باستعمال هذا النّمط في المشاريع الضّخمة كتطبيقات الويب المُعقّدة الّتي تعمل في المتصفّح، إذ تكون الحاجة مُلحّة لتجزئة المشروع وتطوير كلّ جزء بصورة مستقلّة ثم ربط هذه الأجزاء مع بعضها إمّا بهدف تسهيل تطوير المشروع أو إدارة المتطلّبات بحيث تُجلَب عند الحاجة إليها نظرًا لكبر حجمها أو تأثيرها على أداء التّطبيق، كما يُنصح باستخدامه عند الحاجة لعزل تفاصيل الوحدة عن النّطاق العامّ.</p><p>المصادر:</p><ul><li>كتاب <em><a rel="external nofollow" href="http://addyosmani.com/resources/essentialjsdesignpatterns/book/">JavaScript Design Patterns‏</a></em> لمؤلّفه Addy Osmani</li><li>‏<a rel="external nofollow" href="http://www.adequatelygood.com/JavaScript-Module-Pattern-In-Depth.html">JavaScript Module Pattern: In-Depth‏</a></li><li><a rel="external nofollow">وثائق require.js‏</a></li><li><a rel="external nofollow" href="https://nodejs.org/api">وثائق Node.js‏</a></li></ul>]]></description><guid isPermaLink="false">47</guid><pubDate>Mon, 23 Mar 2015 09:28:00 +0000</pubDate></item></channel></rss>
