Spherical Tag Cloud

مقدمه
 Spherical Tag Cloud یکی از شیوه های نمایش برچسب هاست. ابر برچسب ( Tag Cloud ) این روزها اهمیت زیادی پیدا کرده اند. دلیل این امر توانایی آنها در نمایش چند پارامتر به صورت همزمان در قالبی آشنا برای کاربران است. بررسی تفصیلی  Tag Cloud نیازمند نوشته ای جداگانه است.
آنچه در این نوشته قصد داریم بررسی کنیم نحوه ساخت Spherical Tag Cloud است. این نوع نمایش Tag Cloud عبارت است از نمایش برچسب ها به صورتی که گویی بر سطح یک کره نامرئی قرار دارند. اما پا را فراتر نهاده و امکان حرکت این برچسب ها را با سرعت های متفاوت ممکن می سازیم.

قبل از هر کاری سورس کد را دانلود کنید. کامپایل کنید و نتیجه را ببینید. به این ترتیب تصور بهتری نسبت به کاری که قرار است انجام شود خواهید داشت. همچنین می توانید یک نمونه دیگر از این نوع تگها را اینجا ببینید.
برای شروع به کمی اطلاعات هندسی نیاز داریم.

کمی هندسه
مختصات کروی، یکی از انواع دستگاه های مختصات است. چیزی شبیه محتصات دکارتی که در آن و در فضای سه بعدی از سه مقدار x و y و z برای مشخص کردن یک نقطه استفاده می کنیم. در مختصات کروی هر نقطه با سه پرامتر phi، theta و radius مشخص میشود:
تبدیل مختصات کروی به دکارتی نیر بسیار ساده است:




برای این برنامه، مختصات تگ به صورت مختصات کروی ذخیره می شود. به این ترتیب محاسبه محل بعدی تگ بسیار ساده و در حد افزودن مقداری به فیلد نگهدارنده ی Phi و Theta است. مقدار radius را هیچ گاه تغییر نمیدهیم تا تگ ها همیشه روی یک کره ثابت حرکت کنند. اما برای رسم تگ روی فرم، مختصات کروی هر تگ را به مختصات دکارتی تبدیل کرده و روی فرم رسمش می کنیم. 


کمی کدنویسی

کلاس Tag
این کلاس برای دخیره کردن خواص تگ شامل اسم، مختصات کروی و سرعت تغییر مختصات کروی است. همچنین با کمک سه Property عمل تبدیل مختصات کروی به مختصات دکارتی انجام میشود. مختصات دکارتی برای رسم تگها رو فرم به کار می روند.

مقداری اولیه لیست Tag ها
یک حلقه for که به تعداد تگ ها تکرار میشود و هر بار یک نمونه از کلاس Tag را ساخته و مقدار دهی می کند. Radius شعاع کره است که تگ روی آن حرکت میکند. بهتر است برای همه تگها radius برابر باشد. Phi و Teta ( هرچند در واقع Theta است ) مکان تگ را روی کره نشان می دهد. دو فیلد دیگرهم سرعت تغییرات Phi و Teta را نگه میدارند. یعنی در هر فریم چقدر این مقادیر و به تبعیت از آنها، مکان تگ عوض می شود. هر نمونه مقداردهی شده به یک لیست اضافه می شوند.

جا به جا کردن Tag ها
در هر Clock یا فریم، باید مقادیر جدیر مکانی حساب شوند. این کار را متد Clock و با افزودن مقدار سرعت بر کلاک به مختصات کروی هر تگ انجام می دهد. اگر مقدار این تغییر را برای phi غیر فعال کنیم ( در کد کامنت شده است )، تگ ها فقط به صورت افقی دور کره می چرخند. میتوانید این کار را با Teta هم انجام دهید و نتیجه را ببینید.
نکته جالب این است که با کمک مختصات کروی جابه جایی تگها بر سطح کره بسیار ساده شده است و تنها با تغییر مقادیر Phi و Teta، تگ روی سطح کره حرکت می کند. در حالی که اگر از مختصات دکارتی استفاده میکردیم، کار پیچیده تری در انتظار ما بود.
در نهایت لیست تگ ها بر اساس مقدار Z آنها مرتب می شوند (هر چند بهتر بود این کار در بخش نمایش Tag ها انجام می دادیم).
به این ترتیب رسم تگ ها را از کمترین Z (عقب ترین تگ به ببیننده ) شروع میکنیم و به جلوترین تگ می رسیم. به این ترتیب همیشه تگهای جلوتر روی تگهای عقبتر از خود را می پوشانند.

نمایش Tag ها
نمایش تگ ها در ساده ترین حالت فقط شامل یک حلقه برای رسم تک تک تگها به کمک e.Graphics.DrawString است. اما ما کمی جلوه های ویژه نیز به آن افزوده ایم. اول اینکه  تگهای جلوتر با فونت بزرگتری نمایش داده می شوند و دوما تگهای جلوتر پررنگ تر خواهند بود.
برای محاسبه اندازه فونت و رنگ هر تگ باید کمی محاسبه انجام دهیم.
اندازه فونت با توجه به مقدار Z هرتگ محاسبه می شود. Z مقداری بین منفی Radius تا مثبت Radius را کسب میکند و چون فونت نمیتواند سایز منفی داشته باشد، مقدار Z را به انداز Radius انتقال می دهیم تا همواره با مقداری بین صفر تا 2xRadius را کار کنیم و باز هم جون اندازه فونت نمی خواهیم خیلی کوچک باشد مقداری چون 5 را به آن می افزاییم تا کوچکترین فونت حداقل اندازه 5 داشته باشد.
فرض کنیم شعاعی که برای کره در نظر گرفتیم 400 باشد. پس احتمالا نزدیک ترین تگ فونتی با اندازه 805 خواهد بود. و این خیلی بزرگ خواهد بود. پس ضریبی چون 0.1 را در آن ضرب میکنیم تا اندازه معقولی بدست آید. البته انتخاب این ضریب مهم است و میتواند در تبدیل شکل نمایشی از کره به بیضی هم استفاده شود.
برای محاسبه رنگ، با توجه به مقدار Z، یک رنگ بین سفید تا سیاه را انتخاب می کنیم. این مقدار این طور حساب می شود.
ابتدا مقدار Z به بازه بین 0 تا یک انتقال داده می شود.
‏tag.Z + max) / (2 * max)
 سپس این مقدار ضریبی از 255 را تولید میکند:
(((tag.Z + max) / (2 * max)) * 255
و نهایتا از 255 کم می شود تا Z کمتر به سفید نزیکتر و Z بیشتر به سیاه نزدیک تر باشد:
 int scale = 255 - (int)(((tag.Z + max) / (2 * max)) * 255);

نمایش پیوسته
یک تایمر هر 20 میکروثانیه صدا زده میشود و فرم را دوباره رسم میکند. برای نمایش بهتر نیز مقدار DoubleBuffered  را true کرده ایم.

ایده های بیشتر
می توانید این سورس کد را تغییر دهیم و امکانت بیشتری به آن بیافزایید. مثلا:
1- مدیریت برخوردها
میتوانید برای مدیریت برخورد تگها با هم رفتارهایی را پیاده سازی کنید. مثلا پس از برخورد، جهت حرکت تگ ها تغییر کند. شاید هم مایل بودید و از رفتارتان را بر ساس قوانین فیزیکی طراحی کردید.

2- حساسیت به موس
چیزی که خیلی رایج است و با قرار گرفتن موس روی بخشی از کره، تگها جهت حرکتشان را به سمت کرسر موس تغییر میدهند.

3- تبدیل کد برای استفاده در وب
کار ساده ای است که به جاری رسم روی فرم، روی صفحه وب و با استفاده از مختصات مطلق در CSS مکان تگ ها را تعیین کنید. البته در CSS میتوانید از ویژگی جالب مقدار z هم استفاده کنید و مقدار کد را کمی کاهش بدهید. اگر عاقلانه فکر کنید، بهتر است این کد را کدی سمت کلاینت تبدیل کنید تا کدی سمت سرور !

4- برای آنکه نتیجه شبیه نمونه های رایج شود، از مقادیر یکسانی برای PhiVelocity و ،TetaVelocity استفاده کنید.

5- امکان کلیک کردن روی تگ را فراهم کنید.

6- توزیع مکانی تگ ها را مدیریت کنید. بهتر است تگ های کمتری در قطب های کره تجمع کنند. در واقع در حالت ایده آل تنها یک تگ باید در آنجا باشد !
منابع