ক্যানভাসে টাইপোগ্রাফিক প্রভাব

আমার অতীত ইতিহাস

2006 সালে যখন ফায়ারফক্স v2.0 প্রকাশিত হয়েছিল তখন <canvas> আমার সচেতনতায় প্রবেশ করেছিল। Ajaxian- এর উপর একটি নিবন্ধ, রূপান্তর ম্যাট্রিক্সের বর্ণনা, আমাকে আমার প্রথম <canvas> ওয়েব-অ্যাপ তৈরি করতে অনুপ্রাণিত করেছে; রঙের গোলক (2007)। যা আমাকে রঙের জগতে নিমজ্জিত করে, এবং গ্রাফিক আদিম; ব্রাউজারে "পেইন্টের চেয়ে ভাল" একটি অ্যাপ্লিকেশন একসাথে রাখার প্রয়াসে স্কেচপ্যাড (2007-2008) তৈরিতে অনুপ্রাণিত করা। এই পরীক্ষাগুলি শেষ পর্যন্ত আমার দীর্ঘদিনের বন্ধু চার্লস প্রিচার্ডের সাথে স্টার্টআপ মুগটুগ তৈরির দিকে পরিচালিত করে। আমরা HTML5 <canvas>ডার্করুম তৈরি করছি। ডার্করুম হল একটি অ-ধ্বংসাত্মক ফটো-শেয়ারিং অ্যাপ, যা ভেক্টর-ভিত্তিক টাইপোগ্রাফি এবং অঙ্কনের সাথে পিক্সেল-ভিত্তিক ফিল্টারের ক্ষমতাকে একত্রিত করে।

ভূমিকা

ক্যানভাস ব্যানার গ্রাফিক।

<canvas> জাভাস্ক্রিপ্ট প্রোগ্রামারদের তাদের স্ক্রিনে রঙ , ভেক্টর এবং পিক্সেলের সম্পূর্ণ নিয়ন্ত্রণ নিয়ে আসে - মনিটরের ভিজ্যুয়াল মেকআপ।

নিম্নলিখিত উদাহরণগুলি <canvas> -এর একটি এলাকা নিয়ে কাজ করে যেটি খুব বেশি মনোযোগ দেয়নি; টেক্সট ইফেক্ট তৈরি করা। <canvas> -এ তৈরি করা যেতে পারে এমন বিভিন্ন টেক্সট-ইফেক্ট যতটা আপনি কল্পনা করতে পারেন - এই ডেমোগুলি কী সম্ভব তার একটি উপ-বিভাগ কভার করে। যদিও আমরা এই নিবন্ধে "টেক্সট" নিয়ে কাজ করছি, পদ্ধতিগুলি যেকোনো ভেক্টর বস্তুতে প্রয়োগ করা যেতে পারে; গেম এবং অন্যান্য অ্যাপ্লিকেশনগুলিতে উত্তেজনাপূর্ণ ভিজ্যুয়াল তৈরি করা:

<canvas> ক্যানভাসে> টেক্সট-শ্যাডো।
CSS-এর মত টেক্সট-ইফেক্ট <canvas> এ ক্লিপিং মাস্ক তৈরি করা, <canvas> এ মেট্রিক্স খোঁজা, এবং ছায়া বৈশিষ্ট্য ব্যবহার করে।
নিওন-রামধনু, জেব্রা-প্রতিফলন - চেইনিং প্রভাব।
গ্লোবাল কম্পোজিটঅপারেশন, ক্রিয়েটলাইনার গ্রেডিয়েন্ট, ক্রিয়েট প্যাটার্ন ব্যবহার করার উদাহরণ <canvas> ফটোশপের মতো টেক্সট-ইফেক্ট।
<canvas> ক্যানভাসে> ভিতরের এবং বাইরের ছায়া
একটি সামান্য পরিচিত বৈশিষ্ট্য প্রকাশ; একটি ড্রপ-শ্যাডো ( অভ্যন্তরীণ-ছায়া ) এর বিপরীতে তৈরি করতে ঘড়ির কাঁটার দিকে বনাম ঘড়ির কাঁটার বিপরীতে ঘুরানো ব্যবহার করে।
স্পেসেজ - উত্পাদনশীল প্রভাব।
গতির অনুভূতি তৈরি করতে hsl() কালার-সাইক্লিং এবং window.requestAnimationFrame ব্যবহার করে <canvas> -এ জেনারেটিভ ভিত্তিক টেক্সট-ইফেক্ট।

ক্যানভাসে পাঠ্য-ছায়া

CSS3 স্পেক্সে আমার প্রিয় সংযোজনগুলির মধ্যে একটি (বর্ডার-ব্যাসার্ধ, ওয়েব-গ্রেডিয়েন্ট এবং অন্যান্য সহ) হল ছায়া তৈরি করার ক্ষমতা। CSS এবং <canvas> ছায়ার মধ্যে পার্থক্য উপলব্ধি করা গুরুত্বপূর্ণ, বিশেষ করে:

CSS দুটি পদ্ধতি ব্যবহার করে; বক্স-এলিমেন্টের জন্য বক্স-ছায়া , যেমন ডিভ, স্প্যান ইত্যাদি; এবং পাঠ্য বিষয়বস্তুর জন্য পাঠ্য-ছায়া

<canvas> এক ধরনের ছায়া আছে; এটি সমস্ত ভেক্টর বস্তুর জন্য ব্যবহৃত হয়; ctx.moveTo, ctx.lineTo, ctx.bezierCurveTo, ctx.quadradicCurveTo, ctx.arc, ctx.rect, ctx.fillText, ctx.strokeText, এবং আরও অনেক কিছু। <canvas> -এ একটি ছায়া তৈরি করতে, এই চারটি বৈশিষ্ট্যে আলতো চাপুন:

ctx.shadowColor = "লাল" // স্ট্রিং
ছায়ার রঙ; RGB, RGBA, HSL, HEX, এবং অন্যান্য ইনপুট বৈধ।
ctx.shadowOffsetX = 0; // পূর্ণসংখ্যা
পাঠ্যের সাথে সম্পর্কিত ছায়ার অনুভূমিক দূরত্ব।
ctx.shadowOffsetY = 0; // পূর্ণসংখ্যা
টেক্সট সম্পর্কিত ছায়ার উল্লম্ব দূরত্ব।
ctx.shadowBlur = 10; // পূর্ণসংখ্যা
ছায়ায় ঝাপসা প্রভাব, মান যত বড় হবে, তত বেশি ঝাপসা।

জিনিসগুলি শুরু করার জন্য, আসুন দেখি কিভাবে <canvas> CSS প্রভাব অনুকরণ করতে পারে। "css text-shadow" এর জন্য Google ইমেজের মাধ্যমে অনুসন্ধান করা আমাদের অনুকরণ করার জন্য কয়েকটি দুর্দান্ত ডেমোর দিকে পরিচালিত করে; লাইন25 , এবং স্টেরিওস্কোপিক , এবং শ্যাডো 3D

CSS 3D গ্রাফিক

স্টেরিওস্কোপিক 3D ইফেক্ট (আরো জন্য অ্যানাগ্লিফ ইমেজ দেখুন) হল কোডের একটি সাধারণ লাইনের উদাহরণ, যা দারুণ কাজে লাগানো হয়েছে। CSS-এর নিম্নলিখিত লাইনের সাহায্যে, আমরা 3D লাল/সায়ান চশমা (3D মুভিতে যে ধরনের তারা আপনাকে দেয়) দিয়ে দেখলে গভীরতার বিভ্রম তৈরি করতে পারি:

text-shadow: -0.06em 0 0 red, 0.06em 0 0 cyan;

এই স্ট্রিংটিকে <canvas> এ রূপান্তর করার সময় দুটি বিষয় লক্ষ্য করা যায়:

  1. কোন শ্যাডো-ব্লার (তৃতীয় মান) নেই, তাই আসলে ছায়া চালানোর কোন কারণ নেই, যেহেতু fillText একই ফলাফল তৈরি করবে:
var text = "Hello world!"
ctx.fillStyle = "#000"
ctx.fillText(text, -7, 0);
ctx.fillStyle = "red"
ctx.fillText(text, 0, 0);
ctx.fillStyle = "cyan"
ctx.fillText(text, 7, 0);</pre>
  1. EM's <canvas> এ সমর্থিত নয় তাই তাদের PX's-এ রূপান্তর করতে হবে। আমরা DOM-এ একই ফন্ট-বৈশিষ্ট্য সহ একটি উপাদান তৈরি করে এবং পরিমাপ করা ফরম্যাটে প্রস্থ সেট করে PT, PC, EM, EX, PX এবং আরও-এর মধ্যে রূপান্তর করার জন্য রূপান্তর অনুপাত খুঁজে পেতে পারি; অথবা উদাহরণস্বরূপ, EM -> PX রূপান্তর ক্যাপচার করতে, আমরা DOM উপাদানটিকে "উচ্চতা: 1em" দিয়ে পরিমাপ করব, ফলে অফসেট উচ্চতা হবে প্রতিটি EM-এ কতগুলি PX আছে।
var font = "20px sans-serif"
var d = document.createElement("span");
d.style.cssText = "font: " + font + " height: 1em; display: block"
// the value to multiply PX 's by to convert to EM 's
var EM2PX = 1 / d.offsetHeight;</pre>

আলফা-গুণ প্রতিরোধ

আরও জটিল উদাহরণে, যেমন লাইন 25-এ পাওয়া নিয়ন প্রভাব, ছায়া ব্লুর বৈশিষ্ট্য সঠিকভাবে প্রভাব অনুকরণ করতে ব্যবহার করা আবশ্যক। যেহেতু নিয়ন প্রভাব একাধিক ছায়ার উপর নির্ভর করে, আমরা একটি সমস্যায় পড়ি; <canvas> -এ প্রতিটি ভেক্টর বস্তুর শুধুমাত্র একটি ছায়া থাকতে পারে। সুতরাং, একাধিক ছায়া আঁকতে, আপনাকে অবশ্যই নিজের উপরে পাঠ্যের একাধিক সংস্করণ আঁকতে হবে। এর ফলে আলফা সংখ্যাবৃদ্ধি হয়, এবং শেষ পর্যন্ত জ্যাগড প্রান্ত।

নিয়ন গ্রাফিক

ছায়া প্রদর্শন করার সময় আমি ctx.fillStyle = "rgba(0,0,0,0)" বা "transparent" লেখাটি লুকানোর চেষ্টা করেছি… তবে, এই প্রচেষ্টা বৃথা ছিল; যেহেতু ছায়া ফিল স্টাইল আলফার গুণিতক, তাই ছায়া ফিলস্টাইলের চেয়ে বেশি অস্বচ্ছ হতে পারে না।

সৌভাগ্যবশত, এর চারপাশে একটি উপায় আছে, আমরা পাঠ্য থেকে অফসেট ছায়া আঁকতে পারি, সেগুলিকে আলাদা করে রাখতে পারি (যাতে তারা ওভারল্যাপ না হয়), এবং এর ফলে পাঠ্যটিকে পর্দার পাশে লুকিয়ে রাখতে পারি:

var text = "Hello world!"
var blur = 10;
var width = ctx.measureText(text).width + blur * 2;
ctx.textBaseline = "top"
ctx.shadowColor = "#000"
ctx.shadowOffsetX = width;
ctx.shadowOffsetY = 0;
ctx.shadowBlur = blur;
ctx.fillText(text, -width, 0);

একটি টেক্সট ব্লক চারপাশে ক্লিপিং

এটিকে কিছুটা পরিষ্কার করার জন্য আমরা একটি ক্লিপিং পাথ যোগ করে ফিল টেক্সটটিকে প্রথম স্থানে (ছায়া আঁকার অনুমতি দেওয়ার সময়) আঁকতে বাধা দিতে পারি। পাঠ্যের চারপাশে একটি ক্লিপিং পাথ তৈরি করার জন্য, আমাদের পাঠ্যের উচ্চতা (যাকে ঐতিহাসিকভাবে "এম-উচ্চতা" বলা হয় একটি ছাপাখানায় "M" অক্ষরের উচ্চতা) এবং পাঠ্যের প্রস্থ জানতে হবে। আমরা ctx.measureText().width ব্যবহার করে প্রস্থ পেতে পারি, তবে, ctx.measureText().height বিদ্যমান নেই।

সৌভাগ্যবশত, CSS hack-ardry এর মাধ্যমে ( CSS পরিমাপ ব্যবহার করে <canvas> এর পুরানো বাস্তবায়ন ঠিক করার আরও উপায়ের জন্য Typographic Metrics দেখুন ), আমরা একই ফন্ট-বৈশিষ্ট্য সহ <span> এর offsetHeight পরিমাপের মাধ্যমে পাঠ্যের উচ্চতা খুঁজে পেতে পারি। :

var d = document.createElement("span");
d.font = "20px arial"
d.textContent = "Hello world!"
var emHeight = d.offsetHeight;

সেখান থেকে, আমরা একটি ক্লিপিং পাথ হিসাবে ব্যবহার করার জন্য একটি আয়তক্ষেত্র তৈরি করতে পারি; ডামি-আকৃতি অপসারণের সময় "ছায়া" ঘেরা।

ctx.rect(0, 0, width, emHeight);
ctx.clip();

এটিকে একসাথে বেঁধে রাখা, এবং আমরা যেতে যেতে অপ্টিমাইজ করা - যদি একটি ছায়ার কোন অস্পষ্টতা না থাকে, তাহলে fillText একই প্রভাবে ব্যবহার করা যেতে পারে, ক্লিপিং মাস্ক সেট আপ করা থেকে আমাদের বাঁচাতে পারে:

var width = ctx.measureText(text).width;
var style = shadowStyles[text];
// add a background to the current effect
ctx.fillStyle = style.background;
ctx.fillRect(0, offsetY, ctx.canvas.width, textHeight - 1)
// parse text-shadows from css
var shadows = parseShadow(style.shadow);
// loop through the shadow collection
var n = shadows.length; while(n--) {
var shadow = shadows[n];
var totalWidth = width + shadow.blur * 2;
ctx.save();
ctx.beginPath();
ctx.rect(offsetX - shadow.blur, offsetY, offsetX + totalWidth, textHeight);
ctx.clip();
if (shadow.blur) { // just run shadow (clip text)
    ctx.shadowColor = shadow.color;
    ctx.shadowOffsetX = shadow.x + totalWidth;
    ctx.shadowOffsetY = shadow.y;
    ctx.shadowBlur = shadow.blur;
    ctx.fillText(text, -totalWidth + offsetX, offsetY + metrics.top);
} else { // just run pseudo-shadow
    ctx.fillStyle = shadow.color;
    ctx.fillText(text, offsetX + (shadow.x||0), offsetY - (shadow.y||0) + metrics.top);
}
ctx.restore();
}
// drawing the text in the foreground
if (style.color) {
ctx.fillStyle = style.color;
ctx.fillText(text, offsetX, offsetY + metrics.top);
}
// jump to next em-line
ctx.translate(0, textHeight);

যেহেতু আপনি এই সমস্ত <canvas> কমান্ড ম্যানুয়ালি প্রবেশ করতে চান না, তাই আমি ডেমো উত্সে একটি সাধারণ পাঠ্য-ছায়া পার্সার অন্তর্ভুক্ত করেছি; এইভাবে আপনি এটিকে CSS কমান্ড খাওয়াতে পারেন এবং এটি <canvas> কমান্ড তৈরি করতে পারেন। এখন, আমাদের <canvas> উপাদানগুলির শৈলীর একটি সম্পূর্ণ পরিসর রয়েছে যা এটি বাঁধতে পারে। এই একই ছায়া-প্রভাবগুলি যেকোন ভেক্টর বস্তুতে ব্যবহার করা যেতে পারে, WebFonts থেকে SVGs থেকে আমদানি করা জটিল আকারে, জেনারেটিভ ভেক্টর আকারে এবং আরও অনেক কিছুতে!

ক্যানভাস প্রভাবে পাঠ্য ছায়া

ইন্টারমিশন (পিক্সেল-পুশিং-এ স্পর্শক)

নিবন্ধের এই অংশটি লেখার সময়, স্টেরিওস্কোপিক উদাহরণ আমাকে কৌতূহলী করে তুলেছে। <canvas> এবং সামান্য ভিন্ন দৃষ্টিকোণ থেকে নেওয়া দুটি ছবি ব্যবহার করে একটি 3D-মুভি-স্ক্রিন প্রভাব তৈরি করা কতটা কঠিন হবে? দৃশ্যত, খুব কঠিন না. নিম্নলিখিত কার্নেলটি প্রথম চিত্রের (ডেটা) লাল চ্যানেলকে একত্রিত করে এবং দ্বিতীয় চিত্রের সায়ান চ্যানেল (ডেটা2):

data[i] = data[i] * 255 / 0xFF;
data[i+1] = 255 * data2[i+1] / 0xFF;
data[i+2] = 255 * data2[i+2] / 0xFF;

এখন, কাউকে কেবল তাদের কপালে দুটি আইফোনের ডাক্ট-টেপ করতে হবে, একই সময়ে "ভিডিও রেকর্ড করুন" এ ক্লিক করতে হবে এবং আমরা HTML5-এ আমাদের নিজস্ব 3D চলচ্চিত্র তৈরি করতে পারি৷ কোন স্বেচ্ছাসেবক?

3D চশমা

নিয়ন-রামধনু, জেব্রা-প্রতিফলন-চেইনিং প্রভাব

<canvas> -এ একাধিক প্রভাব চেইন করা সহজ হতে পারে, কিন্তু Global CompositeOperation (GCO) এর একটি প্রাথমিক জ্ঞান প্রয়োজন। জিআইএমপি (বা ফটোশপ) এর সাথে অপারেশনগুলির তুলনা করতে: <canvas> 12টি জিসিও রয়েছে গাঢ় , এবং লাইটারকে লেয়ার ব্লেন্ড-মোড হিসাবে ভাবা যেতে পারে; অন্যান্য 10টি অপারেশন আলফা মাস্ক হিসাবে স্তরগুলিতে প্রয়োগ করা হয় (এক স্তর অন্য স্তরের পিক্সেলগুলিকে সরিয়ে দেয়)। গ্লোবাল কম্পোজিট অপারেশন "স্তর" (অথবা আমাদের ক্ষেত্রে, কোডের স্ট্রিং) একত্রে সংযুক্ত করে, নতুন এবং উত্তেজনাপূর্ণ উপায়ে তাদের একত্রিত করে:

চেইনিং ইফেক্ট গ্রাফিক্স

গ্লোবাল কম্পোজিটঅপারেশন চার্ট কর্মক্ষেত্রে GCO মোড দেখায়; এই চার্টটি কালার-স্পেকট্রামের একটি বড় অংশ এবং আলফা স্বচ্ছতার একাধিক স্তর ব্যবহার করে বিস্তারিতভাবে দেখতে কী আশা করা যায়। আমি পাঠ্য বিবরণের জন্য Mozilla এর Global CompositeOperation রেফারেন্স চেক করার সুপারিশ করব। আরও গবেষণার জন্য, আপনি পোর্টার ডাফের কম্পোজিটিং ডিজিটাল ইমেজে অপারেশনটি কীভাবে কাজ করে তা শিখতে পারেন।

আমার প্রিয় মোড হল globalCompositeOperation="lighter"। লাইটার কিভাবে আলো মিশ্রিত হয় অনুরূপ সংযুক্ত পিক্সেল মিশ্রিত হয়; যখন লাল, সবুজ এবং সাদা আলো পূর্ণ-তীব্রতায় থাকে, তখন আমরা সাদা-আলো দেখতে পাই। এটির সাথে খেলার জন্য এটি একটি উত্তেজনাপূর্ণ বৈশিষ্ট্য, বিশেষ করে যখন <canvas> কম গ্লোবাল আলফাতে সেট করা হয়; সূক্ষ্ম নিয়ন্ত্রণ সক্ষম, এবং মসৃণ প্রান্ত. লাইটার অনেক ব্যবহার করা হয়েছে, আমার সাম্প্রতিক প্রিয় একটি HTML5 ডেস্কটপ ব্যাকগ্রাউন্ড স্রষ্টা http://weavesilk.com/ এ পাওয়া যায়। আমার ডেমোগুলির মধ্যে একটি, Breathing Galaxies (JS1k), এছাড়াও লাইটার মোড ব্যবহার করে - এই দুটি উদাহরণ থেকে প্যাটার্ন অঙ্কন করলে আপনি দেখতে শুরু করেন যে এই মোডটি কী প্রভাব ফেলে।

গ্লোবাল কম্পোজিট অপারেশন ব্রাউজার হ্যান্ডলিং

নিওন-রেইনবো জিটার ইফেক্ট

নিম্নোক্ত ডেমোতে, আমরা গ্লোবাল কম্পোজিট অপারেশন (সোর্স-ইন, লাইটার এবং গাঢ়) ব্যবহার করে একত্রে ইফেক্ট চেইন করার মাধ্যমে, একটি বিচলিত রূপরেখা সহ একটি ফটোশপের মতো নিওন-রেইনবো-গ্লো অর্জন করতে যাচ্ছি। এই ডেমোটি "টেক্সট-শ্যাডোস ইন <canvas> " ডেমোর একটি অগ্রগতি, পাঠ্য থেকে ছায়াকে আলাদা করার ক্ষেত্রে একই কৌশল ব্যবহার করে (আগের বিভাগটি দেখুন):

রংধনু জিটার
function neonLightEffect() {
var text = "alert('"+String.fromCharCode(0x2665)+"')";
var font = "120px Futura, Helvetica, sans-serif";
var jitter = 25; // the distance of the maximum jitter
var offsetX = 30;
var offsetY = 70;
var blur = getBlurValue(100);
// save state
ctx.save();
ctx.font = font;
// calculate width + height of text-block
var metrics = getMetrics(text, font);
// create clipping mask around text-effect
ctx.rect(offsetX - blur/2, offsetY - blur/2,
        offsetX + metrics.width + blur, metrics.height + blur);
ctx.clip();
// create shadow-blur to mask rainbow onto (since shadowColor doesn't accept gradients)
ctx.save();
ctx.fillStyle = "#fff";
ctx.shadowColor = "rgba(0,0,0,1)";
ctx.shadowOffsetX = metrics.width + blur;
ctx.shadowOffsetY = 0;
ctx.shadowBlur = blur;
ctx.fillText(text, -metrics.width + offsetX - blur, offsetY + metrics.top);
ctx.restore();
// create the rainbow linear-gradient
var gradient = ctx.createLinearGradient(0, 0, metrics.width, 0);
gradient.addColorStop(0, "rgba(255, 0, 0, 1)");
gradient.addColorStop(0.15, "rgba(255, 255, 0, 1)");
gradient.addColorStop(0.3, "rgba(0, 255, 0, 1)");
gradient.addColorStop(0.5, "rgba(0, 255, 255, 1)");
gradient.addColorStop(0.65, "rgba(0, 0, 255, 1)");
gradient.addColorStop(0.8, "rgba(255, 0, 255, 1)");
gradient.addColorStop(1, "rgba(255, 0, 0, 1)");
// change composite so source is applied within the shadow-blur
ctx.globalCompositeOperation = "source-atop";
// apply gradient to shadow-blur
ctx.fillStyle = gradient;
ctx.fillRect(offsetX - jitter/2, offsetY,
            metrics.width + offsetX, metrics.height + offsetY);
// change composite to mix as light
ctx.globalCompositeOperation = "lighter";
// multiply the layer
ctx.globalAlpha = 0.7
ctx.drawImage(ctx.canvas, 0, 0);
ctx.drawImage(ctx.canvas, 0, 0);
ctx.globalAlpha = 1
// draw white-text ontop of glow
ctx.fillStyle = "rgba(255,255,255,0.95)";
ctx.fillText(text, offsetX, offsetY + metrics.top);
// created jittered stroke
ctx.lineWidth = 0.80;
ctx.strokeStyle = "rgba(255,255,255,0.25)";
var i = 10; while(i--) { 
    var left = jitter / 2 - Math.random() * jitter;
    var top = jitter / 2 - Math.random() * jitter;
    ctx.strokeText(text, left + offsetX, top + offsetY + metrics.top);
}    
ctx.strokeStyle = "rgba(0,0,0,0.20)";
ctx.strokeText(text, offsetX, offsetY + metrics.top);
ctx.restore();
};

জেব্রা প্রতিফলন প্রভাব

জেব্রা রিফ্লেকশন ইফেক্টটি WebDesignerWall- এর চমৎকার রিসোর্স দ্বারা অনুপ্রাণিত হয়েছে কিভাবে CSS দিয়ে আপনার পৃষ্ঠাকে মশলাদার করা যায়। এটি ধারণাটিকে আরও কিছুটা এগিয়ে নিয়ে যায়, পাঠ্যটির জন্য একটি "প্রতিফলন" তৈরি করে - যেমন আপনি আইটিউনসে যা দেখতে পারেন৷ প্রভাবটি ফিল কালার (সাদা), তৈরি প্যাটার্ন (zebra.png) এবং লিনিয়ার গ্রেডিয়েন্ট (চকচকে) একত্রিত করে; এটি প্রতিটি ভেক্টর অবজেক্টে একাধিক ফিল টাইপ প্রয়োগ করার ক্ষমতাকে চিত্রিত করে:

জেব্রা প্রভাব
function sleekZebraEffect() {
// inspired by - http://www.webdesignerwall.com/demo/css-gradient-text/
var text = "Sleek Zebra...";
var font = "100px Futura, Helvetica, sans-serif";

// save state
ctx.save();
ctx.font = font;

// getMetrics calculates:
// width + height of text-block
// top + middle + bottom baseline
var metrics = getMetrics(text, font);
var offsetRefectionY = -20;
var offsetY = 70;
var offsetX = 60;

// throwing a linear-gradient in to shine up the text
var gradient = ctx.createLinearGradient(0, offsetY, 0, metrics.height + offsetY);
gradient.addColorStop(0.1, '#000');
gradient.addColorStop(0.35, '#fff');
gradient.addColorStop(0.65, '#fff');
gradient.addColorStop(1.0, '#000');
ctx.fillStyle = gradient
ctx.fillText(text, offsetX, offsetY + metrics.top);

// draw reflected text
ctx.save();
ctx.globalCompositeOperation = "source-over";
ctx.translate(0, metrics.height + offsetRefectionY)
ctx.scale(1, -1);
ctx.font = font;
ctx.fillStyle = "#fff";
ctx.fillText(text, offsetX, -metrics.height - offsetY + metrics.top);
ctx.scale(1, -1);

// cut the gradient out of the reflected text 
ctx.globalCompositeOperation = "destination-out";
var gradient = ctx.createLinearGradient(0, offsetY, 0, metrics.height + offsetY);
gradient.addColorStop(0.0, 'rgba(0,0,0,0.65)');
gradient.addColorStop(1.0, '#000');
ctx.fillStyle = gradient;
ctx.fillRect(offsetX, offsetY, metrics.width, metrics.height);

// restore back to original transform state
ctx.restore();

// using source-atop to allow the transparent .png to show through to the gradient
ctx.globalCompositeOperation = "source-atop";

// creating pattern from <image> sourced.
ctx.fillStyle = ctx.createPattern(image, 'repeat');

// fill the height of two em-boxes, to encompass both normal and reflected state
ctx.fillRect(offsetX, offsetY, metrics.width, metrics.height * 2);
ctx.restore();
};

ক্যানভাসে অভ্যন্তরীণ/বাহ্যিক ছায়া

<canvas> স্পেক্স "অভ্যন্তরীণ" বনাম "বাহ্যিক" ছায়ার বিষয়কে স্পর্শ করে না। প্রকৃতপক্ষে, প্রথম উপস্থিতিতে, আপনি আশা করতে পারেন যে "অভ্যন্তরীণ" ছায়া সমর্থিত নয়। এই ক্ষেত্রে না হয়. এটি সক্ষম করা একটু কৌশলী ;) F1LT3R- এর সাম্প্রতিক পোস্টে প্রস্তাবিত হিসাবে, আপনি ঘড়ির কাঁটা বনাম ঘড়ির কাঁটার বিপরীতে ঘুরার নিয়মের অনন্য বৈশিষ্ট্যগুলি ব্যবহার করে অভ্যন্তরীণ-ছায়া তৈরি করতে পারেন। এটি করার জন্য, আপনি কন্টেইনার আয়তক্ষেত্র অঙ্কন করে একটি "অভ্যন্তরীণ-ছায়া" তৈরি করুন এবং তারপরে, বিপরীত ঘূর্ণন নিয়ম ব্যবহার করে, একটি কাটআউট আকৃতি আঁকুন - আকৃতির বিপরীত তৈরি করুন।

নীচের উদাহরণটি অভ্যন্তরীণ-ছায়া এবং ফিল স্টাইলকে একই সাথে রঙ + গ্রেডিয়েন্ট + প্যাটার্নের সাথে স্টাইলাইজ করার অনুমতি দেয়। আপনি পৃথকভাবে প্যাটার্ন ঘূর্ণন নির্দিষ্ট করতে পারেন; লক্ষ্য করুন জেব্রা স্ট্রাইপগুলি এখন একে অপরের সাথে লম্ব। বাউন্ডিং-বক্সের আকারের একটি ক্লিপিং মাস্ক ব্যবহার করা হয় একটি অতি-বড় পাত্রের প্রয়োজনীয়তা দূর করার জন্য কাটআউটের আকৃতি ঘেরাও করার জন্য - ছায়ার অপ্রয়োজনীয় অংশগুলিকে প্রক্রিয়া করা থেকে রোধ করে গতি উন্নত করে।

ভিতরের/বাহ্যিক ছায়া
function innerShadow() {

function drawShape() { // draw anti-clockwise
ctx.arc(0, 0, 100, 0, Math.PI * 2, true); // Outer circle
ctx.moveTo(70, 0);
ctx.arc(0, 0, 70, 0, Math.PI, false); // Mouth
ctx.moveTo(-20, -20);
ctx.arc(30, -30, 10, 0, Math.PI * 2, false); // Left eye
ctx.moveTo(140, 70);
ctx.arc(-20, -30, 10, 0, Math.PI * 2, false); // Right eye
};

var width = 200;
var offset = width + 50;
var innerColor = "rgba(0,0,0,1)";
var outerColor = "rgba(0,0,0,1)";

ctx.translate(150, 170);

// apply inner-shadow
ctx.save();
ctx.fillStyle = "#000";
ctx.shadowColor = innerColor;
ctx.shadowBlur = getBlurValue(120);
ctx.shadowOffsetX = -15;
ctx.shadowOffsetY = 15;

// create clipping path (around blur + shape, preventing outer-rect blurring)
ctx.beginPath();
ctx.rect(-offset/2, -offset/2, offset, offset);
ctx.clip();

// apply inner-shadow (w/ clockwise vs. anti-clockwise cutout)
ctx.beginPath();
ctx.rect(-offset/2, -offset/2, offset, offset);
drawShape();
ctx.fill();
ctx.restore();

// cutout temporary rectangle used to create inner-shadow
ctx.globalCompositeOperation = "destination-out";
ctx.fill();

// prepare vector paths
ctx.beginPath();
drawShape();

// apply fill-gradient to inner-shadow
ctx.save();
ctx.globalCompositeOperation = "source-in";
var gradient = ctx.createLinearGradient(-offset/2, 0, offset/2, 0);
gradient.addColorStop(0.3, '#ff0');
gradient.addColorStop(0.7, '#f00');
ctx.fillStyle = gradient;
ctx.fill();

// apply fill-pattern to inner-shadow
ctx.globalCompositeOperation = "source-atop";
ctx.globalAlpha = 1;
ctx.rotate(0.9);
ctx.fillStyle = ctx.createPattern(image, 'repeat');
ctx.fill();
ctx.restore();

// apply fill-gradient
ctx.save();
ctx.globalCompositeOperation = "destination-over";
var gradient = ctx.createLinearGradient(-offset/2, -offset/2, offset/2, offset/2);
gradient.addColorStop(0.1, '#f00');
gradient.addColorStop(0.5, 'rgba(255,255,0,1)');
gradient.addColorStop(1.0, '#00f');
ctx.fillStyle = gradient
ctx.fill();

// apply fill-pattern
ctx.globalCompositeOperation = "source-atop";
ctx.globalAlpha = 0.2;
ctx.rotate(-0.4);
ctx.fillStyle = ctx.createPattern(image, 'repeat');
ctx.fill();
ctx.restore();

// apply outer-shadow (color-only without temporary layer)
ctx.globalCompositeOperation = "destination-over";
ctx.shadowColor = outerColor;
ctx.shadowBlur = 40;
ctx.shadowOffsetX = 15;
ctx.shadowOffsetY = 10;
ctx.fillStyle = "#fff";
ctx.fill();
};

এই উদাহরণগুলি থেকে আপনি দেখতে পাচ্ছেন, গ্লোবাল কম্পোজিট অপারেশন ব্যবহার করে, আমরা একসাথে চেইন-ইফেক্ট করতে পারি, আরও বিস্তৃত প্রভাব তৈরি করতে পারি (মাস্কিং এবং মিশ্রন ব্যবহার করে)। পর্দা আপনার ঝিনুক;)

স্পেসেজ-উৎপাদনশীল প্রভাব

<canvas> এ, ইউনিকোড অক্ষর 0x2708 থেকে যাচ্ছে:

ইউনিকোড gfaphic

…এই ছায়াযুক্ত উদাহরণে:

ছায়াযুক্ত উদাহরণ

…একটি পাতলা লাইন প্রস্থ (0.25) সহ ctx.strokeText() এ একাধিক কলের মাধ্যমে অর্জন করা যেতে পারে, যখন ধীরে ধীরে x-অফসেট এবং আলফা হ্রাস করা হয়; আমাদের ভেক্টর উপাদানগুলিকে গতির অনুভূতি প্রদান করে।

সাইন/কোসাইন তরঙ্গে XY পজিশনের উপাদান ম্যাপ করে এবং HSL প্রপার্টি ব্যবহার করে রঙের মাধ্যমে সাইকেল চালানোর মাধ্যমে আমরা আরও আকর্ষণীয় প্রভাব তৈরি করতে পারি, যেমন এই "বায়োহাজার্ড" উদাহরণ:

এইচএসএল সাইক্লিং প্রভাব

এইচএসএল: হিউ, স্যাচুরেশন, লাইটনেস (1978)

HSL হল CSS3 স্পেক্সে একটি নতুন সমর্থিত বিন্যাস। যেখানে HEX কম্পিউটারের জন্য ডিজাইন করা হয়েছিল, HSL কে মানুষের পাঠযোগ্য করার জন্য ডিজাইন করা হয়েছে।

এইচএসএল এর স্বাচ্ছন্দ্য চিত্রিত করা; রঙ-বর্ণালীতে ঘুরতে, আমরা কেবলমাত্র 360 থেকে "হ্যু" বৃদ্ধি করব; রঙ নলাকার ফ্যাশনে বর্ণালীতে ম্যাপ করা হয়। হালকাতা নিয়ন্ত্রণ করে যে রঙ কতটা গাঢ়/হালকা হয়; 0% একটি কালো পিক্সেল নির্দেশ করে, যেখানে 100% একটি সাদা পিক্সেল নির্দেশ করে। স্যাচুরেশন একটি রঙ কতটা উজ্জ্বল বা প্রাণবন্ত তা নিয়ন্ত্রণ করে; ধূসর গুলি 0% এর সম্পৃক্ততার সাথে তৈরি করা হয় এবং 100% এর মান ব্যবহার করে প্রাণবন্ত রং তৈরি করা হয়।

এইচএসএল গ্রাফিক

যেহেতু HSL একটি সাম্প্রতিক মান, আপনি পুরানো ব্রাউজারগুলিকে সমর্থন করা চালিয়ে যেতে চাইতে পারেন, যা রঙ-স্পেস রূপান্তরের মাধ্যমে সম্ভব। নিম্নলিখিত কোডটি একটি HSL অবজেক্ট গ্রহণ করে { H: 360, S: 100, L: 100} এবং একটি RGB অবজেক্ট { R: 255, G: 255, B: 255 } আউটপুট করে। সেখান থেকে, আপনি আপনার rgb বা rgba স্ট্রিং তৈরি করতে সেই মানগুলি ব্যবহার করতে পারেন। আরও গভীর তথ্যের জন্য এইচএসএল- এর উপর উইকিপিডিয়ার অন্তর্দৃষ্টিপূর্ণ নিবন্ধটি দেখুন।

// HSL (1978) = H: Hue / S: Saturation / L: Lightness
HSL_RGB = function (o) { // { H: 0-360, S: 0-100, L: 0-100 }
var H = o.H / 360,
    S = o.S / 100,
    L = o.L / 100,
    R, G, B, _1, _2;

function Hue_2_RGB(v1, v2, vH) {
if (vH < 0) vH += 1;
if (vH > 1) vH -= 1;
if ((6 * vH) < 1) return v1 + (v2 - v1) * 6 * vH;
if ((2 * vH) < 1) return v2;
if ((3 * vH) < 2) return v1 + (v2 - v1) * ((2 / 3) - vH) * 6;
return v1;
}

if (S == 0) { // HSL from 0 to 1
R = L * 255;
G = L * 255;
B = L * 255;
} else {
if (L < 0.5) {
    _2 = L * (1 + S);
} else {
    _2 = (L + S) - (S * L);
}
_1 = 2 * L - _2;

R = 255 * Hue_2_RGB(_1, _2, H + (1 / 3));
G = 255 * Hue_2_RGB(_1, _2, H);
B = 255 * Hue_2_RGB(_1, _2, H - (1 / 3));
}

return {
R: R,
G: G,
B: B
};
};

অনুরোধ অ্যানিমেশনফ্রেম দিয়ে অ্যানিমেশন তৈরি করা

অতীতে, জাভাস্ক্রিপ্টে অ্যানিমেশন তৈরি করতে, দুটি পছন্দ ছিল; setTimeout , এবং setInterval

window.requestAnimationFrame , এখানে উভয় প্রতিস্থাপনের জন্য নতুন স্ট্যান্ডার্ড; ব্রাউজারকে উপলব্ধ সংস্থানগুলির উপর ভিত্তি করে অ্যানিমেশনগুলি নিয়ন্ত্রণ করার অনুমতি দিয়ে বিশ্ব বিদ্যুৎ (এবং আপনার কম্পিউটারের কয়েকটি হার্টবিট) সংরক্ষণ করুন৷ কিছু গুরুত্বপূর্ণ বৈশিষ্ট্য অন্তর্ভুক্ত:

  • যখন একজন ব্যবহারকারী ফ্রেমটি বিদ্যমান থাকে, তখন অপ্রয়োজনীয় সম্পদের ব্যবহার রোধ করতে অ্যানিমেশনটি ধীর বা সম্পূর্ণভাবে বন্ধ হয়ে যেতে পারে।
  • 60FPS-এ ফ্রেম-রেটের একটি সীমা ক্যাপ রয়েছে৷ এর কারণ হ'ল এটি মানুষের লক্ষ্য করা স্তরের অনেক উপরে (30FPS দ্বারা বেশিরভাগ মানুষ অ্যানিমেশনকে "তরল" হতে দেখে)।

লেখার সময়, requestAnimationFrame ব্যবহার করার জন্য ভেন্ডারের নির্দিষ্ট উপসর্গের প্রয়োজন হয়। পল আইরিশ একটি শিম স্তর তৈরি করেছেন যাতে ক্রস-ভেন্ডার সমর্থন রয়েছে, স্মার্ট অ্যানিমেশনের জন্য অনুরোধ অ্যানিমেশনফ্রেমে :

// shim layer with setTimeout fallback
window.requestAnimFrame = (function(){
return  window.requestAnimationFrame       || 
        window.webkitRequestAnimationFrame || 
        window.mozRequestAnimationFrame    || 
        window.oRequestAnimationFrame      || 
        window.msRequestAnimationFrame     || 
        function(/* function */ callback, /* DOMElement */ element){
        window.setTimeout(callback, 1000 / 60);
        };
})();

এটিকে আরও কিছুটা এগিয়ে নিয়ে গেলে, আরও উচ্চাভিলাষী এটিকে একটি পলি-ফিলের সাথে সংযুক্ত করতে পারে যেমন requestAnimationFrame.js (কিছু বৈশিষ্ট্য রয়েছে যা কাজ করতে হবে) যা এই নতুন স্ট্যান্ডার্ডে স্যুইচ করার সময় পুরানো ব্রাউজারগুলিকে আরও বেশি পরিমাণে সমর্থন করবে। .

(function animate() {
var i = 50;
while(i--) {
    if (n > endpos) return;

    n += definition;
    ctx.globalAlpha = (0.5 - (n + startpos) / endpos) * alpha;
    if (doColorCycle) {
        hue = n + color;
        ctx.strokeStyle = "hsl(" + (hue % 360) + ",99%,50%)"; // iterate hue
    }
    var x = cos(n / cosdiv) * n * cosmult; // cosine
    var y = sin(n / sindiv) * n * sinmult; // sin
    ctx.strokeText(text, x + xoffset, y + yoffset); // draw rainbow text
}
timeout = window.requestAnimationFrame(animate, 0);
})();
নোট ব্লার গ্রাফিক
অ্যানিমেশন গ্রাফিক
ম্যাট্রিক্স গ্রাফিক

সোর্স কোড

ব্রাউজার বিক্রেতা-গোলক জুড়ে সমর্থন সহ, <canvas> এর ভবিষ্যত সম্পর্কে কোন প্রশ্ন নেই এটি PhoneGap ব্যবহার করে iPhone/Android/Desktop এক্সিকিউটেবলগুলিতে পোর্ট করা যেতে পারে, অথবা

টাইটানিয়াম