@xingwangzhe/tags-cloud: محرك السحابة ثلاثية الأبعاد متعدد الوسائط المبني على الرياضيات البحتة
@xingwangzhe/tags-cloud: محرك السحابة ثلاثية الأبعاد متعدد الوسائط المبني على الرياضيات البحتة
GitHub: xingwangzhe/tags-cloud · Demo: tagscloud.needhelp.icu · npm: @xingwangzhe/tags-cloud · الترخيص: MIT · الإصدار: v0.9.0
1. مقدمة: إعادة تصور سحابة العلامات ثلاثية الأبعاد للويب الحديث
سحابة العلامات (Tag Cloud) هي عنصر أساسي في تصور الويب لأكثر من عقدين، حيث تطورت من قوائم كلمات مرجحة بسيطة إلى تجارب ثلاثية الأبعاد غامرة تأسر المستخدمين وتحول مجموعات النصوص العادية إلى منحوتات مكانية تفاعلية. من بين المساهمات الأكثر تأثيرًا في هذا التطور هو cong-min/TagCloud، وهي مكتبة جافا سكريبت خفيفة الوزن أثبتت كيف يمكن تحقيق كرة من تسميات النص الدوارة بأقل قدر من التعقيد وبدون أي تبعيات خارجية. مع 390 نجمة و 93 fork على GitHub، أسست TagCloud الأصلية نمط تصميم تبناه عدد لا يحصى من المطورين لمواقع المحافظ، وعرض المهارات، ولوحات معلومات تصور البيانات. يكمن ابتكارها الأساسي في إثبات أن السحب ثلاثية الأبعاد لا تحتاج إلى الاعتماد على أطر WebGL الثقيلة أو محركات عرض خارجية؛ بدلاً من ذلك، يمكن للحسابات المثلثية المباشرة مع تحديد موضع DOM الدقيق أن تنتج نتائج بصرية مقنعة بشكل مفاجئ.
نقدم لكم @xingwangzhe/tags-cloud — إعادة تصور من الألف إلى الياء لمفهوم سحابة العلامات ثلاثية الأبعاد التي تحافظ على الأناقة الرياضية لسابقتها مع توسيع قدراتها بشكل كبير، وتحديث بنيتها، ودفع حدود ما يمكن أن تعرضه سحابة العلامات. هذه ليست مجرد fork أو إضافة ميزة؛ إنها تمثل تحولًا معماريًا جذريًا من عارض نصي فقط يعتمد على DOM إلى محرك متعدد الوسائط قادر على عرض النصوص والصور ورسومات SVG ومحتوى HTML التعسفي وعناصر الفيديو وحتى Web Components — كلها تدور معًا في فضاء ثلاثي الأبعاد دقيق رياضيًا. تحقق المكتبة هذه المرونة مع الحفاظ على بصمة مدمجة للغاية تبلغ حوالي 3KB مضغوطة (gzipped)، وتحمل صفر تبعيات تشغيلية، ومبنية بسلسلة أدوات حديثة تمامًا تتكون من Bun كبيئة تشغيل جافا سكريبت، وVite كأداة تجميع، وTypeScript لسلامة الأنواع الكاملة في جميع أنحاء قاعدة الكود.
شعار المشروع — “سحابة علامات ثلاثية الأبعاد متعددة الوسائط · محرك رياضي بحت” — يلخص هويته المزدوجة. من ناحية، هي مكتبة مكونات واجهة مستخدم عملية يمكن للمطورين إسقاطها في أي مشروع ويب لإنشاء كرات علامات مذهلة بصريًا. من ناحية أخرى، هي محرك رياضي يقوم بتحليل المشكلة المعقدة لعرض سحابة العلامات ثلاثية الأبعاد إلى ثلاث عمليات هندسية بحتة وحتمية وقابلة للفصل بشكل جميل: توزيع كرة فيبوناتشي لتحديد المواقع الأولية، ضرب مصفوفة التدوير للتحويل المكاني، والإسقاط المنظوري للعرض ثنائي الأبعاد مع مراعاة العمق. كل من هذه العمليات منفذة في وحدة مخصصة خاصة بها داخل دليل src/core/، مما يجعل قاعدة الكود ليست فقط عالية الصيانة ولكن أيضًا موردًا تعليميًا ممتازًا لأي شخص يسعى لفهم الرياضيات وراء رسومات الكمبيوتر ثلاثية الأبعاد دون تعقيد خط أنابيب العرض الكامل.
توفر الأقسام التالية غوصًا تقنيًا شاملاً في كل جانب من جوانب @xingwangzhe/tags-cloud، بدءًا من خوارزمية توزيع الكرة المشتقة من النسبة الذهبية وصولاً إلى نموذج التفاعل arcball المستوحى من quaternion، ومن بنية العرض المزدوجة Canvas/DOM إلى اعتبارات التصميم المتجاوب التي تجعلها تعمل بسلاسة عبر أجهزة سطح المكتب والهواتف المحمولة. سواء كنت مطورًا يقيم هذه المكتبة لمشروعك القادم، أو مبرمج رسومات مهتمًا بتقنيات ثلاثية الأبعاد خفيفة الوزن، أو عالم رياضيات فضوليًا حول التطبيقات الواقعية لشبكة فيبوناتشي، تقدم هذه المقالة شروحات مفصلة، واشتقاقات رياضية، ورسوم بيانية معمارية، وأمثلة كود مشروحة لتضيء كل وجه من أوجه قطعة الهندسة البرمجية الرائعة هذه.
2. الأساس الرياضي: ثلاث ركائز للعرض ثلاثي الأبعاد
في قلب @xingwangzhe/tags-cloud توجد ثلاثية من العمليات الرياضية التي، عند تركيبها، تحول قائمة مجردة من عناصر المحتوى إلى كرة دوارة متماسكة بصريًا. هذه العمليات — التوزيع، التدوير، والإسقاط — منفذة في ثلاث وحدات مخصصة تحت src/core/، كل منها مسؤولة عن تحويل هندسي واحد. هذا الفصل بين المسؤوليات ليس مجرد تفضيل معماري؛ إنه يعكس البنية الأساسية لخطوط أنابيب رسومات الكمبيوتر ثلاثية الأبعاد، حيث توليد الرؤوس، وتحويل النموذج، وإسقاط الكاميرا هي مراحل متميزة يمكن تحسينها واختبارها وفهمها بشكل مستقل.
flowchart LR
subgraph Input["📥 طبقة الإدخال"]
TAGS["TagItem[]
(text | image | SVG | HTML | video | element)"]
OPTS["TagCloudOptions
(radius, spin, colors, callbacks)"]
end
subgraph CoreEngine["⚙️ محرك رياضي بحت (src/core/)"]
direction TB
DIST["🔵 distribution.ts
كرة فيبوناتشي
N نقاط → إحداثيات ثلاثية الأبعاد"]
ROT["🟢 rotation.ts
مصفوفات التدوير
نقاط ثلاثية الأبعاد → نقاط ثلاثية الأبعاد مدورة"]
PROJ["🔴 projection.ts
الإسقاط المنظوري
نقاط مدورة ثلاثية الأبعاد → ثنائية الأبعاد + عمق"]
end
subgraph RenderLayer["🎨 طبقة العرض"]
direction TB
CANVAS["Canvas 2D API
(نصوص + صور)"]
DOM["DOM Overlay
(SVG + HTML + فيديو + عناصر)"]
end
subgraph Interaction["👤 طبقة التفاعل"]
MOUSE["سحب الماوس / اللمس"]
INERTIA["اضمحلال القصور الذاتي
(0.96/إطار)"]
end
TAGS --> DIST
OPTS --> DIST
DIST -->|"Vec3[]"| ROT
ROT -->|"Rotated Vec3[]"| PROJ
PROJ -->|"ProjectedTag[]
(x, y, z, scale, alpha)"| CANVAS
PROJ --> DOM
MOUSE --> INERTIA
INERTIA -->|"زوايا التدوير"| ROT
style CoreEngine fill:#1a1a2e,stroke:#16213e
style Input fill:#0f3460,stroke:#16213e
style RenderLayer fill:#533483,stroke:#16213e
style Interaction fill:#e94560,stroke:#16213e,color:#fff
2.1 توزيع كرة فيبوناتشي: الهندسة الذهبية لوضع النقاط
الخطوة الأولى والأكثر أهمية من الناحية الجمالية في إنشاء سحابة علامات ثلاثية الأبعاد هي تحديد مكان وضع كل علامة على الكرة. قد تضع طريقة ساذجة العلامات على فترات منتظمة من خطوط الطول والعرض، لكن هذا يؤدي حتمًا إلى التكدس عند القطبين، حيث تتلاقى خطوط الطول، ومناطق متفرقة بالقرب من خط الاستواء. خوارزمية كرة فيبوناتشي تحل هذه المشكلة بأناقة من خلال إنتاج توزيع للنقاط متجانس بشكل ملحوظ عبر سطح الكرة بالكامل، دون أي تكدس أو فجوات مرئية بغض النظر عن عدد النقاط.
تستمد هذه الخوارزمية اسمها من النسبة الذهبية (\varphi = \frac{1 + \sqrt{5}}{2} \approx 1.6180339887)، وهو ثابت رياضي يظهر في جميع أنحاء الطبيعة في هياكل تتراوح من ترتيبات بذور عباد الشمس إلى حلزونات أصداف النوتي. العلاقة بأرقام فيبوناتشي — المتسلسلة حيث كل حد هو مجموع الحدين السابقين — هي أن نسبة أرقام فيبوناتشي المتتالية تتقارب إلى النسبة الذهبية مع تقدم المتسلسلة. في سياق توزيع الكرة، ensures لاعقلانية النسبة الذهبية أن النقاط المتتالية توضع دائمًا بزوايا لا تتكرر أبدًا، مما يخلق نمطًا حلزونيًا لا دوريًا يملأ سطح الكرة بالتساوي.
التنفيذ المحدد في src/core/distribution.ts يستخدم تباينًا من شبكة فيبوناتشي تم تحسينها للتعيين الكروي. لكرة نصف قطرها (R) مع (N) نقطة لتوزيعها، تحسب الخوارزمية الإحداثيات الكروية ثم تحولها إلى إحداثيات ديكارتية ((x, y, z)) لكل نقطة (i \in {0, 1, 2, \ldots, N-1}). زاوية خط العرض (\phi) (المقاسة من المحور z الموجب، أي القطب الشمالي) تحسب باستخدام دالة جيب التمام العكسي لضمان توزيع موحد على طول المحور z:
تضع هذه الصيغة النقطة الأولى أسفل القطب الشمالي قليلاً والنقطة الأخيرة فوق القطب الجنوبي قليلاً، مع إزاحة (+0.5) (المضمنة في البسط (2i + 1)) التي تضمن عدم هبوط أي نقطة بالضبط على قطب. هذا التعديل الدقيق حاسم لأنه يمنع الأثر البصري لعلامة تجلس مباشرة في أعلى أو أسفل الكرة حيث سيكون التدوير بالكاد محسوسًا. تحول دالة (\arccos) معاملًا خطيًا موزعًا بشكل منتظم إلى توزيع زاوي مرجح بجيب التمام، مما يعوض حقيقة أن الكرات لها مساحة سطح أقل بالقرب من القطبين وأكثر بالقرب من خط الاستواء.
زاوية خط الطول (\theta) (المقاسة في المستوى xy من المحور x الموجب) تحسب باستخدام قياس (\phi) بواسطة (\sqrt{N\pi})، مما يخلق النمط الحلزوني المميز:
العامل (\sqrt{N\pi}) مشتق من العلاقة بين الزاوية الذهبية ومساحة السطح الكلية للكرة. مع زيادة (N)، يضمن هذا القياس أن الحلزون يلتف حول الكرة العدد المناسب من المرات للحفاظ على تباعد موحد بين النقاط المتجاورة. النتيجة هي نمط حيث كل نقطة متتالية يتم تدويرها بحوالي الزاوية الذهبية (\approx 137.5°) بالنسبة لسابقتها عند النظر إليها على طول المحور z، مما يعكس الحلزونات التاكسونومية (phyllotactic) الموجودة في الطبيعة.
أخيرًا، يتم تحويل هذه الإحداثيات الكروية إلى إحداثيات ديكارتية باستخدام التحويل القياسي:
النقاط الناتجة تحقق معادلة الكرة (x_i^2 + y_i^2 + z_i^2 = R^2) ويتم توزيعها بتجانس ينافس طرقًا أكثر تكلفة حسابيًا قائمة على التحسين. الملخص التالي يوضح خوارزمية كرة فيبوناتشي الكاملة:
تنفيذ TypeScript في src/core/distribution.ts موجز بشكل ملحوظ، مما يعكس البساطة الأنيقة للخوارزمية:
export interface Vec3 { x: number; y: number; z: number; }
export function fibonacciSphere(n: number, R: number): Vec3[] { const points: Vec3[] = []; for (let i = 0; i < n; i++) { const phi = Math.acos(-1 + (2 * i + 1) / n); const theta = Math.sqrt(n * Math.PI) * phi; points.push({ x: R * Math.cos(theta) * Math.sin(phi), y: R * Math.sin(theta) * Math.sin(phi), z: R * Math.cos(phi), }); } return points;}ترجع هذه الدالة مصفوفة من كائنات Vec3 التي تعمل كمواقع أولية لجميع العلامات في السحابة. تعمل الخوارزمية في زمن (\mathcal{O}(N))، مما يجعلها مناسبة لسحب العلامات التي تحتوي على مئات العناصر. في الممارسة العملية، تحتوي معظم سحب العلامات على ما بين 20 و 100 علامة، حيث يكون هذا الحساب فوريًا تقريبًا.
2.2 التدوير ثلاثي الأبعاد: ضرب المصفوفات في المجال المكاني
بمجرد وضع العلامات على سطح الكرة، الخطوة التالية هي تمكين التدوير — سواء الدوران التلقائي المستمر أو تفاعل السحب بقيادة المستخدم. تنفذ المكتبة التدوير باستخدام مصفوفات تدوير مركبة محاذية للمحاور، وتحديدًا التدويرات المتتالية حول المحور Y متبوعة بالمحور X. هذا الأسلوب فعال حسابيًا، وسهل الفهم، وكافٍ تمامًا لحالة استخدام سحابة العلامات حيث تكون التدويرات دائمًا نسبة إلى كرة مركزها نقطة الأصل.
الأساس الرياضي لهذه التدويرات يأتي من الجبر الخطي. مصفوفة التدوير ثلاثية الأبعاد هي مصفوفة متعامدة (3 \times 3) بمحدد 1 تحول إحداثيات نقطة مع الحفاظ على بعدها من نقطة الأصل. للتدوير بزاوية (\alpha) حول المحور Y، مصفوفة التدوير (R_y(\alpha)) هي:
للتدوير بزاوية (\beta) حول المحور X، مصفوفة التدوير (R_x(\beta)) هي:
تطبق المكتبة هذه التدويرات بشكل متسلسل: أولاً التدوير حول المحور Y، ثم التدوير حول المحور X. لنقطة (P = (x, y, z))، ينتج التدوير حول المحور Y نقطة وسيطة (P’):
ثم يتم تطبيق التدوير حول المحور X على (P’) لإنتاج النقطة المدورة النهائية (P’’):
تنفيذ src/core/rotation.ts يوسع ضرب المصفوفات هذا إلى عمليات حسابية مباشرة، متجنبًا عبء تخصيص كائنات المصفوفات وضربها. لنقطة واحدة، تحسب دالة التدوير:
دالة rotatePoints تؤدي هذا التحويل على دفعة لجميع العلامات:
export function rotatePoints(points: Vec3[], a: number, b: number): Vec3[] { const sinA = Math.sin(a), cosA = Math.cos(a); const sinB = Math.sin(b), cosB = Math.cos(b); return points.map((p) => { const y1 = p.y * cosA + p.z * -sinA; const z1 = p.y * sinA + p.z * cosA; const x2 = p.x * cosB + z1 * sinB; return { x: x2, y: y1, z: z1 * cosB - p.x * sinB }; });}2.3 الإسقاط المنظوري: من الفضاء ثلاثي الأبعاد إلى الشاشة ثنائية الأبعاد
العملية الرياضية النهائية تحول الإحداثيات ثلاثية الأبعاد المدورة إلى مواقع شاشة ثنائية الأبعاد. تستخدم المكتبة نموذج إسقاط مبسط لكنه فعال للغاية يحسب عامل مقياس وعامل شفافية بناءً على العمق، مع معامل عمق منظور يساوي ضعف نصف قطر الكرة:
عامل الشفافية (alpha) يستخدم علاقة تربيعية مع تعديل الانحياز:
خط أنابيب الإسقاط الكامل ملخص كالتالي:
تنفيذ TypeScript يعكس هذه الرياضيات بدقة:
export function project( points: { x: number; y: number; z: number }[], depth: number,): ProjectedTag[] { const d2 = 2 * depth; return points.map((p) => { const per = d2 / (d2 + p.z); const alpha = Math.min(1, Math.max(0, per * per - 0.25)); return { x: p.x, y: p.y, z: p.z, scale: per, alpha }; });}3. العمارة وتصميم الوحدات
تجسد قاعدة الكود عمارة برمجية نظيفة من خلال الفصل المتعمد بين الحساب الرياضي، وتنسيق العرض، ومعالجة تفاعل المستخدم.
3.1 محرك الرياضيات البحتة: src/core/
| الوحدة | الوظيفة | الإدخال | الإخراج | الصيغة الرئيسية |
|---|---|---|---|---|
| distribution.ts | fibonacciSphere(n, R) | N, R | Vec3[] | (\phi_i = \arccos(-1 + \frac{2i+1}{N})) |
| rotation.ts | rotatePoints(points, a, b) | Vec3[], a, b | Vec3[] | (R_y(a)) · (R_x(b)) · (P) |
| projection.ts | project(points, depth) | Vec3[], d | ProjectedTag[] | per = 2d/(2d+z), (\alpha) = per(^2) - 0.25 |
3.2 نظام العرض المزدوج: Canvas + DOM
من أهم الابتكارات هو نظام العرض المزدوج، باستخدام Canvas 2D API للنصوص والصور، وDOM overlay لـ SVG و HTML والفيديو و Web Components.
flowchart TB
subgraph "أنواع العلامات والعارضين"
direction LR
TEXT["📄 علامة نصية"]
IMG["🖼️ علامة صورة"]
SVG_TAG["🎨 علامة SVG"]
HTML_TAG["🌐 علامة HTML"]
VIDEO["🎬 علامة فيديو"]
ELEMENT["🔧 علامة عنصر"]
end
subgraph "اختيار العارض"
CANVAS["Canvas 2D API
✅ نصوص
✅ صور"]
DOM["DOM Overlay
✅ SVG
✅ HTML
✅ فيديو
✅ Web Components"]
end
TEXT --> CANVAS
IMG --> CANVAS
SVG_TAG --> DOM
HTML_TAG --> DOM
VIDEO --> DOM
ELEMENT --> DOM
style CANVAS fill:#0f3460,stroke:#e94560,color:#fff
style DOM fill:#533483,stroke:#e94560,color:#fff
4. خصائص الأداء
4.1 التعقيد الحسابي
| المرحلة | التعقيد | العمليات السائدة |
|---|---|---|
| التدوير | O(N) | 8 ضرب + 4 جمع لكل نقطة |
| الإسقاط | O(N) | 1 قسمة + 2 ضرب + 1 جمع لكل نقطة |
| فرز Z | O(N log N) | فرز بالمقارنة |
| عرض Canvas | O(N) | استدعاءات fillText / drawImage |
| تحديث DOM | O(N) | تعيين transform + opacity |
4.2 كفاءة الذاكرة
لـ (N = 100) علامة، الحالة الرقمية الإجمالية حوالي (100 \times (3 + 5) \times 8 = 6,400) بايت — أقل من 7KB من أرقام الفاصلة العائمة.
4.3 حجم الحزمة
| التنسيق | الحجم |
|---|---|
| ESM (dist/index.js) | ~12 KB |
| Gzip | ~3 KB |
| Brotli | ~2.5 KB |
5. المحتوى متعدد الوسائط: ستة أنواع من العلامات
| نوع العلامة | تنسيق الإدخال | العارض | التفاعلية | حالة الاستخدام |
|---|---|---|---|---|
| نص | string | Canvas 2D | استدعاء onTagClick | مهارات، كلمات مفتاحية |
| صورة | { type:“image”, src, w, h } | Canvas 2D | onClick لكل علامة | شعارات، صور شخصية |
| SVG | { type:“svg”, content, w, h } | DOM | onClick لكل علامة | أيقونات متجهة |
| HTML | { type:“html”, html } | DOM | onClick لكل علامة | نص منسق غني |
| فيديو | { type:“video”, src, w, h } | DOM | شاشة كاملة عند النقر | مقاطع توضيحية |
| عنصر | { type:“element”, element } | DOM | أحداث DOM أصلية | Web Components |
6. مقارنة مع cong-min/TagCloud
| الجانب | cong-min/TagCloud | @xingwangzhe/tags-cloud | التحسين |
|---|---|---|---|
| اللغة | JavaScript (ES5) | TypeScript | سلامة كاملة للأنواع |
| حجم الحزمة | ~6KB مصغر | ~3KB مضغوط (gzipped) | أصغر بحوالي 50% |
| التبعيات | 0 | 0 | كلاهما بلا تبعيات |
| أنواع العلامات | نص فقط | نص، صورة، SVG، HTML، فيديو، عنصر | 6x وسائط محتوى |
| العارض | DOM فقط | Canvas 2D + DOM هجين | أداء أفضل |
| أداة البناء | Rollup + Babel | Vite + Bun + Oxlint | سلسلة أدوات حديثة |
| تفاعل السحب | سحب أساسي بالماوس | نمط Arcball + قصور ذاتي | إحساس أكثر طبيعية |
| دعم اللمس | غير صريح | لمس كامل + CSS للمحمول | جاهز للمحمول |
7. دليل الاستخدام العملي
7.1 سحابة نصية فقط أساسية
import { TagCloud } from "@xingwangzhe/tags-cloud";
const container = document.getElementById("cloud")!;new TagCloud(container, { tags: ["TypeScript", "React", "Vue", "Svelte", "Node.js", "Bun", "Rust"], radius: 250, spinY: 0.12, color: "#e0e0e0", fontSize: 16,});7.2 سحابة متعددة الوسائط
new TagCloud(container, { tags: [ "TypeScript", { type: "image", src: "/avatar.webp", width: 40, height: 40 }, { type: "svg", content: `<svg viewBox="0 0 24 24"><circle cx="12" cy="12" r="10"/></svg>`, width: 48, height: 48 }, { type: "video", src: "/demo.mp4", width: 120, height: 68 }, ], radius: 300, spinY: 0.15, onTagClick(item) { console.log("Clicked:", item); },});7.3 إدارة دورة الحياة
const cloud = new TagCloud(container, { tags, spinY: 0.2 });cloud.setTags(["New", "Set", "Of", "Tags"]);cloud.pause();cloud.resume();cloud.destroy();8. الخلاصة: الرياضيات كمحرك عرض
يقف @xingwangzhe/tags-cloud كدليل مقنع على أن أقوى محرك عرض في البرمجيات ليس GPU أو مترجم تظليل أو إطار عمل — بل هو الرياضيات. من خلال تحليل مشكلة عرض سحابة العلامات ثلاثية الأبعاد إلى ثلاث عمليات رياضية بحتة — توزيع كرة فيبوناتشي، ضرب مصفوفة التدوير، والإسقاط المنظوري — تحقق المكتبة نتائج لا يمكن تمييزها بصريًا عن بدائل WebGL مع عدم الحاجة إلى أي من تعقيداتها أو تبعياتها الأجهزية أو وزن حزمتها.
مساهمات المشروع في النظام البيئي مفتوح المصدر ثلاثية. معماريًا، تثبت أن العارض الهجين Canvas/DOM يمكن أن يوفر كلًا من الأداء والتنوع ضمن حزمة 3KB. رياضيًا، توفر تطبيقات نظيفة وموثقة جيدًا لخوارزميات رسومات ثلاثية الأبعاد أساسية. عمليًا، تعطي المطورين مكونًا جاهزًا للإسقاط لإنشاء سحب علامات ثلاثية الأبعاد مع دعم الوسائط الغنية، وسلامة أنواع TypeScript، وتفاعل جاهز للمحمول — كل ذلك دون إضافة تبعية واحدة.
نهاية المقال — بناءً على تحليل كود المصدر لـ @xingwangzhe/tags-cloud v0.9.0