التعليقات التوضيحية
إضافة دعم التعليقات التوضيحية إلى العارض
تعمل التعليقات التوضيحية في Doconut في اتجاهين: يرسمها المستخدمون في ودجت المتصفح ويقوم الخادم بحفظها لكل صفحة، أو يبنيها الكود برمجياً ويحملها في جلسة مفتوحة. في كلتا الحالتين تُعرض على الصفحات ويمكن دمجها في تصديرات PDF/PNG.
يتم تفعيل دعم التعليقات التوضيحية عبر قدرة الترخيص Annotation (تُمنح تلقائياً ضمن ترخيص مؤقت نشط).
تمكين واجهة المستخدم للتعليقات التوضيحية
التعليقات التوضيحية هي وحدة Viewer، ليست شريط أدوات مستقل. يجب أن تشمل الصفحة الكاملة موارد Viewer، شريط أدوات Viewer، تثبيت Viewer، وobjViewer المهيأ؛ ثم يتم تثبيت شريط التعليقات التوضيحية وربطه بنفس المثيل.
أصدر حزم التعليقات التوضيحية جنباً إلى جنب مع حزم العارض — فهي مقيدة بالترخيص، لذا تظهر العلامات فقط عندما تكون القدرة متاحة:
@Html.Raw(Viewer.ReferenceCss(new CssConfig
{
IncludeViewerCss = true,
IncludeAnnotationCss = true // jquery-ui.min.css + annotationBar.css
}))
@Html.Raw(Viewer.ReferenceScripts(new ScriptConfig
{
IncludeJQuery = true,
IncludeViewerScripts = true,
IncludeAnnotationScripts = true, // jquery-ui, raphael.js, annotation.js
IncludeAnnotationBar = true // the embedded annotation ribbon
}))احفظ تركيبة Viewer الكاملة مرئية في العلامات:
<nav id="toolbar" aria-label="Document viewer controls">
<!-- عناصر تحكم العارض، بما في ذلك الزر الذي يفتح التعليقات التوضيحية -->
</nav>
<div id="annBarMount"></div>
<div id="divDocViewer"><div id="div_ctlDoc"></div></div>تُنشئ حزمة التعليقات التوضيحية شريط الـ Ribbon داخل annBarMount؛ لا تحتاج إلى نسخ أزراره أو علامات حوار الـ markup. ابدأ بتهيئة docViewer أولاً، ثم أنشئ الـ Ribbon فقط عندما يؤكد الخادم أن التعليقات التوضيحية مرخصة:
<script>
let annBar = null;
let currentToken = '';
const objViewer = $('#div_ctlDoc').docViewer({
BasePath: 'doconut',
ResPath: 'doconut-res/images',
onAnnLoaded: () => annBar?.handleAnnLoaded(),
onAnnSaved: () => annBar?.handleAnnSaved(),
onAnnSaveError: () => annBar?.handleAnnSaveError(),
onAnnClosed: () => annBar?.handleAnnClosed(),
onError: (message) => console.error('Viewer error:', message)
});
@if (Viewer.IsAnnotationEnabled)
{
<text>
annBar = $('#annBarMount').doconutAnnotationBar({
docId: 'ctlDoc',
getRequestParams: () => ({ token: currentToken }),
onStatus: (message) => console.log(message),
onToast: (message, type) => console.log(type, message),
onLayout: () => requestAnimationFrame(() => objViewer.Refit())
});
annBar.attach(objViewer);
</text>
}
</script>حفظ البيانات من الـ Ribbon يرسلها عبر الطبقة الوسيطة (AnnSave)، التي تخزنها في جلسة المستند لكل صفحة. التحميل (AnnLoad) يحدث تلقائياً عندما تُعرض صفحة تحتوي على تعليقات توضيحية. تُبقي الاستدعاءات الأربعة onAnn* الـ Ribbon متزامناً مع دورة حياة العارض.
افتحه وأغلقه من أي شريط أدوات Viewer مملوك للمضيف:
annBar.open();
annBar.close();واجهة برمجة التطبيقات العامة للـ Ribbon هي:
| Method | Purpose |
|---|---|
attach(objViewer) | ربط الشريط بالعارض المهيأ؛ مطلوب مرة واحدة |
open() / close() | بدء أو إنهاء تحرير التعليقات التوضيحية |
reset() | إعادة الشريط إلى حالته المغلقة غير القابلة للتحرير |
isOpen() / annotating() | قراءة حالة الشريط / حالة تحرير التعليقات في العارض |
reopenEditable() | إعادة تحميل تعليقات الصفحة الحالية ككائنات قابلة للتحرير |
updateActionState() | تحديث توفر عناصر التحكم حفظ/حذف بعد تغييرات المضيف |
headerSlot() | الحصول على فتحة التوسيع الاختيارية في الرأس لعناصر التحكم المملوكة للمضيف |
onStatus، onToast، onLayout، onEditStart، وonEditEnd هي استدعاءات اختيارية من المضيف. يمكن لكائن endpoints أيضاً توفير exportPdf، exportPng، imageUpload، وimageList؛ تظل العناصر التي لا تمتلك نقطة نهاية مُكوَّنة مخفية.
لسلسلة بدء التشغيل المدمجة للـ Viewer، والبحث، والتعليقات التوضيحية، راجع البدء السريعQuick Start.
تضيف حزمة التعليقات التوضيحية أدوات التأليف في المتصفح، لكن البيانات لا تزال تابعة لجلسة المستند على الخادم المحددة بالرمز المميز. إعادة فتح المصدر تُنشئ جلسة جديدة؛ احفظ الـ XML أو غلاف التعليقات المشفر في تطبيقك إذا كان يجب أن تبقى التعليقات التوضيحية موجودة بعد انتهاء مدة الجلسة.
إنشاء التعليقات التوضيحية في C#
احصل على مدير مرتبط بالجلسة المفتوحة، أضف التعليقات التوضيحية، وحمّلها (باستخدام using Doconut.Annotations; للأنواع و using System.Drawing; لـ Rectangle/Color):
app.MapPost("/api/annotations/load-sample", (string token, Viewer viewer) =>
{
// مرتبط بأبعاد صفحة الجلسة المفتوحة
var manager = viewer.GetAnnotationManager(token);
var pageCount = viewer.GetPageCount(token);
// طابع واحد لكل صفحة
for (int page = 1; page <= pageCount; page++)
{
manager.Add(new StampAnnotation(page, new Rectangle(30, 20, 240, 90),
$"PAGE {page}", 28, 4, Color.Maroon)
{
Opacity = 60,
Rotate = -8
});
}
manager.Add(new NoteAnnotation(1, new Rectangle(420, 150, 220, 120),
"Loaded from C# code.", Color.FromArgb(255, 255, 255, 170), 14));
// تحميل إلى الجلسة — الواجهة تجلبها عبر AnnLoad و
// المُعالج يحرقها في تصديرات الصورة/PDF.
viewer.LoadAnnotationData(token, manager);
return Results.Ok();
});أنواع التعليقات التوضيحية
جميع الأنواع موجودة في Doconut.Annotations وتورث من BaseAnnotation (رقم الصفحة + Rectangle المحيط):
| النوع | ملاحظات |
|---|---|
StampAnnotation | طابع نصي مع حجم الخط، حد، لون؛ يدعم Opacity، Rotate |
NoteAnnotation | ملاحظة لاصقة مع نص، لون خلفية، حجم خط، TitleColor |
RectangleAnnotation | حد + ألوان تعبئة، Title/ShowTitle |
CircleAnnotation | حد + تعبئة، ShowBorder |
EllipseAnnotation | حد + تعبئة، ShowBorder |
TriangleAnnotation | لون الحد، BackColor، ShowBorder |
LineAnnotation | خط مستقيم بعرض ولون |
ArrowAnnotation | خط مع رأس سهم؛ قابل لتعيين Direction (النوع ArrowDirection، نقاط البوصلة، الافتراضي E) |
FreehandAnnotation | ضربة حرة من نقاط FreehandData المشفرة |
ImageAnnotation | صورة من عنوان URL. يتم حل عنوان URL النسبى بالنسبة لمضيف الطلب عندما تُضاف التعليقة (يتم جلب الصورة فقط وقت الحرق) — يجب أن يكون قابلًا للوصول من الخادم (مثلاً ملف تحت wwwroot يُقدم بواسطة UseStaticFiles). |
واجهة برمجة تطبيقات AnnotationManager
| العضو | الغرض |
|---|---|
Add(BaseAnnotation) | إضافة تعليق توضيحي إلى الطابور |
GetAnnotations() / GetAnnotations(int page) | فحص ما يحتفظ به المدير |
ClearAnnotations() / ClearAnnotations(int page) | إزالة جميع التعليقات / حسب الصفحة |
GetAnnotationData() / GetAnnotationData(int page) | سلسلة بيانات التعليقات المشفرة — غلاف Base64 (ما تستهلكه الواجهة) |
GetAnnotationXml() | شكل XML |
Viewer يعكس عمليات التحميل/القراءة مقابل جلسة: LoadAnnotationData(token, manager) أو LoadAnnotationData(token, encodedData) (غلاف Base64 من GetAnnotationData())، LoadAnnotationXML(token, xml)، GetAnnotationXML(token).
تصدير مع دمج التعليقات التوضيحية
// PDF لجميع الصفحات مع التعليقات التوضيحية المرسومة عليها
app.MapGet("/api/annotations/export-pdf", async (string token, Viewer viewer) =>
{
byte[] pdf = await viewer.ExportAnnotationsToPdfAsync(token, zoom: 100);
return Results.File(pdf, "application/pdf", "export.pdf");
});
// أو ملف ZIP للصور PNG لكل صفحة
app.MapGet("/api/annotations/export-png-zip", async (string token, Viewer viewer) =>
{
byte[] zip = await viewer.ExportAnnotationsToPngZipAsync(token, zoom: 100);
return Results.File(zip, "application/zip", "annotations-png.zip");
});تستخدم عمليات التصدير نفس المحرك المستخدم في العرض على الشاشة، لذا ما يراه المستخدمون هو ما يحتويه الملف.
سير عمل الحفظ
- افتح المستند واحصل على رمزه.
- حمّل XML أو البيانات المشفرة المخزنة مسبقًا إلى ذلك الرمز.
- اسمح للواجهة بقراءة وتحرير تعليقات الجلسة.
- استرجع XML باستخدام
GetAnnotationXML(token)عندما يقرر تطبيقك حفظ البيانات. - صدّر PDF/PNG عندما يكون التسليم المسطح مطلوبًا.
- أغلق جلسة المستند.
لا تستخدم رمز المشاهد غير الشفاف كمعرف دائم للتعليقات التوضيحية. اربط البيانات المحفوظة للتعليقات بمعرفات المستند والإصدار الخاصة بك.
ملاحظات الأمان والعرض
- طلبات التعليق تستخدم نفس أمان الجلسة/الرمز المميز كما في طلبات الصفحات.
- عنوان URL نسبي لـ
ImageAnnotationيتم حله من مضيف الطلب ويجب أن يظل قابلاً للوصول إلى الخادم عند وقت التحويل. - تحقق وتحكم في أي عنوان URL للصور مقدم من المستخدم لتجنب تزوير طلبات الخادم.
- التصديرات تطبق نفس قرار الترخيص/العلامة المائية المخصصة كما في عرض الصفحة على الشاشة.
- الأحمال الكبيرة للرسومات الحرة والتصديرات عالية الدقة تزيد من استهلاك الذاكرة؛ اختبر المستندات الواقعية وقيم التكبير.
استكشاف الأخطاء وإصلاحها
| العَرَض | التحقق |
|---|---|
| شريط التعليقات مفقود | ميزة Annotation وأربع علامات CSS/script للتعليقات |
| إبلاغ رد الاتصال للحفظ عن خطأ | انتهاء صلاحية الرمز المميز/الجلسة وBasePath للوسيط |
| التعليقات C# لا تظهر | ترقيم الصفحات يبدأ من واحد والبيانات تم تحميلها إلى الرمز المميز النشط |
| تظهر التعليقات على الصورة على الشاشة لكنها غير موجودة في التصدير | الخادم يمكنه الوصول إلى عنوان URL للصورة أثناء التحويل |
| المستند المعاد فتحه لا يحتوي على تعليقات | احفظ XML/البيانات خارج جلسة المشاهد، ثم حمّلها إلى الرمز المميز الجديد |
هل كانت هذه الصفحة مفيدة؟