টেকডায়েরির নতুন ফিচার: Progress Circle

সোমবার, ১০ মে ২০২১, রাত ৩:৫৫ সময়

টেকডায়েরি তে নতুন নতুন কিছু না কিছু ফিচার নিয়ে আসছি আমরা। গত বছর থেকে বাংলাদেশের প্রোগ্রামারদের জন্যে এমন একটা জায়গা তৈরি করার চেষ্টা করছি যেখানে সবার knowledge একে অপরের সাথে শেয়ার করবে। আপনারা অনেকে আর্টিকেল পড়তে গিয়ে খেয়াল করলে দেখবেন ডেস্কটপের বামে নতুন একটা Circle তৈরি হয় যখন আপনি scroll করতে থাকেন। আমি কয়দিন ধরে এরকম একটা ফিচার আনতে চাচ্ছিলাম যেখানে আর্টিকেল রিডাররা দেখতে পারে তারা কতটুকু পড়ল। কয়েকদিন পড়াশুনা করে একটা বানিয়ে ফেললাম। চলুন আপনাদেরকে দেখাই কিভাবে আমি এটা বানিয়েছি। 

এটা তৈরি করার জন্যে দুইটা জিনিস মাথায় রাখতে হবে

  1. একটা component তৈরি করব যেখানে আমরা একটা বৃত্ত (ring/circle) svg বানাবো, সেটা কে animate করব 
  2. আমরা দেখব একটা নির্দিষ্ট div থেকে কিভাবে dynamic ভাবে percantage ভ্যালু পেতে পারি DOM element থেকে

প্রথম স্টেপঃ SVG রিং (ring) তৈরি করা

HTML আর CSS অনেক ভাবেই ইচ্ছে করলে রিং টা করা যেত কিন্তু আমার কাছে SVG টা ভাল লাগে কারণ এটা দিয়ে খুব সহজে style করা যায় সব ধরণের screen এর resolution ঠিক রেখে

<svg
  class="progress-ring"
  height="120"
  width="120"
>
  <circle
    class="progress-ring__circle"
    stroke-width="1"
    fill="transparent"
    r="58"
    cx="60"
    cy="60"
  />
</svg>

<svg> element এর ভিতরে  একটা <circle> ট্যাগ  আছে, যেখানে আমরা r attribute দিয়ে রিং এর ব্যাসার্ধ (radius), cx এবং cy দিয়ে    আমরা SVG ViewBox এর center থেকে circle টার অবস্থান  আর সার্কেলের stroke-width (এক কোথায় বলতে গেলে border বা বৃত্যের বাইরের লাইনের এর প্রস্থ) বলে দিয়েছি।

লক্ষ করলে দেখতে পারব যে circle এর ব্যাসার্ধ (radius) 58, 60 নয়

radius = (width / 2) - (strokeWidth * 2)

তার মানে আমরা বুঝতে পারছি যে যদি আমরা stroke বাড়াতে চাই, তাহলে আমাদের ব্যাসার্ধ কমাতে হবে, যেমন stroke যদি 4 হয় তাহলে ব্যাসার্ধ হবে 52

52 = (120 / 2) - (4 * 2)

<svg> এর <circle> টা যাতে বুঝা যায় তার জন্যে আমাদের fill টাকে transparent করতে হবে এবং stroke এর একটা color দিতে হবে

দ্বিতীয় স্টেপঃ Stroke যুক্ত করা

এই স্টেপে আমরা রিং এর লাইনটা কে animate করব। এখানে আমরা দুইটা CSS Properties ব্যবহার করব, stroke-dasharray আর  stroke-dashoffset। 

stroke-dasharray

এটা অনেকটা border-style:dashed এর মত, কিন্তু পার্থক্য হচ্ছে এখানে ওই dash গুলার width আর দুইটা dash এর gap বলে দেয়া যায়

.progress-ring__circle {
  stroke-dasharray: 10 20;
}

এই ভ্যালু দিলে আমাদের রিং এর dash গুলা 10px বড় যেখানে দুইটা dash এর মধ্যে 20px দূরত্ব আছে, দেখতে অনেকটা এরকম হবে

stroke-dashoffset

এটা আমাদেরকে stroke এর dash-gap গুলার starting point টা সরাতে সাহায্য করে svg path এর।

এখন, মনে করি আমরা বৃত্যের পরিধি stroke-dasharray এর দুই ভ্যালুতেই দিলাম। তাহলে কি দাঁড়াল? একটা বড় dash হবে এবং একি ভ্যালুর একটা বড় gap ও হবে যেটা দেখা যাবে না। কিন্তু যদি আমরা dash-offset এ পরিধির ভ্যালু থেকে কমাতে শুরু করি তাহলে বৃত্যটার অংশ দেখা যাবে। 

এটা নিয়ে কয়েক বছর আগে, Jake Archibald এর আর্টিকেলে এটার সুন্দর ব্যাখ্যা দিয়েছেন, আপনারা চাইলে পড়তে পারেন আরও ভালোভাবে বুঝার জন্যে। 

পরিধি 

আমাদের পরধির মান দরকার সেটার জন্যে আমরা ত্রিকোণামিত্রির এই সূত্র দিয়ে বের করতে পারি

circumference = radius * 2 * PI

আমরা এই সূত্র ব্যবহার করে খুব সহজেই জাভাস্ক্রিপ্ট দিয়ে এই মান বের করতে পারি

const circle = document.querySelector('.progress-ring__circle');
const radius = circle.r.baseVal.value;
const circumference = radius * 2 * Math.PI;

পরে আমরা এটা দিয়ে style দিতে পারি circle element এ

circle.style.strokeDasharray = `${circumference} ${circumference}`;
circle.style.strokeDashoffset = circumference;

তৃতীয় স্টেপঃ Progress to offset

আমাদের মাথায় রাখতে হবে, stroke-dashoffset এর মান যখন 0 হবে তার মানে আমাদের progress টা শেষ হবে। তাই progress বাড়ানোর জন্যে আমাদের এই ফাংশন টা ব্যবহার করতে হবেঃ

function setProgress(percent) {
  const offset = circumference - percent / 100 * circumference;
  circle.style.strokeDashoffset = offset;
}

animation এর জন্যে এই css টা দিতে পারি 

.progress-ring__circle {
  transition: stroke-dashoffset 0.35s;
  transform: rotate(-90deg);
  transform-origin: 50% 50%,
}

এটাকে আরও ভালোভাবে ব্যবহার করতে চাইলে একটা component এর ভিতরে রাখলে খুব গুছানো হবে আপনার Application এ ব্যবহার করতে চাইলে

Web Component হিসেবে ব্যবহার করতে চাইলে

আমাদের এখন HTML আছে, লজিক আছে, CSS আছে আমরা ইচ্ছে করলে যেকোনো framework এ ব্যবহার করতে পারি

চলুন আমরা দেখি কিভাবে web component হিসেবে ব্যবহার করতে পারবেন

Vue Component হিসেবে ব্যবহার করতে চাইলে

React Component হিসেবে ব্যবহার করতে চাইলে

এইতো গেল component কিন্তু এই component এ percantage ভ্যালু টা dynamically কিভাবে দিব যখন scroll করতে থাকব সেটা দেখব

চতুর্থ স্টেপঃ percentage ভ্যালু dynamic করা 

এখানে প্রথমে আমরা একটা snippet দেখব 

const articleContent = document.querySelector('article');
const scrollTop = window.scrollY,
  contentOffsetTop = articleContent.offsetTop,
  contentHeight = articleContent.clientHeight,
  innerHeight = window.innerHeight;
let getPercentage = Math.round(
  ((scrollTop - contentOffsetTop) / (contentHeight - innerHeight)) * 100
);
  • window.scrollY - হচ্ছে page এর একদম উপর থেকে কতটুকু scroll হল সেটা জানার জন্যে
  • articleContent.offsetTop - হচ্ছে পেইজের একদম উপর থেকে একটা specific div পর্যন্ত দূরত্ব জানতে (এখানে আমরা আর্টিকেল ধরে নিচ্ছি) 
  • articleContent.clientHeight - হচ্ছে একটা specific div এর height জানার জন্যে। 
  • window.innerHeight - হচ্ছে পেইজের কতটুকু অংশ viewport আছে বা কত height আপনি দেখতে পারছেন

আর আসল ফর্মুলাটা হচ্ছে 

Math.round(
  ((scrollTop - contentOffsetTop) / (contentHeight - innerHeight)) * 100

আমি একটা Demo বানিয়েছি