التعليقات التوضيحية
إضافة دعم التعليقات التوضيحية إلى العارض
تعمل التعليقات التوضيحية في 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">
<!-- Viewer controls, including the button that opens Annotation -->
</nav>
<div id="annBarMount"></div>
<div id="divDocViewer"><div id="div_ctlDoc"></div></div>حزمة التعليقات التوضيحية تُنشئ شريط الـ Ribbon داخل annBarMount؛ لا تحتاج إلى نسخ أزراره أو علامات الحوار. قم بتهيئة 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 العامة هي:
| الطريقة | الغرض |
|---|---|
attach(objViewer) | ربط الـ Ribbon بالعارض المُهيأ؛ مطلوب مرة واحدة |
open() / close() | بدء أو إنهاء تحرير التعليقات التوضيحية |
reset() | إرجاع الـ Ribbon إلى حالته المغلقة غير القابلة للتحرير |
isOpen() / annotating() | قراءة حالة الـ Ribbon / حالة تحرير التعليقات في العارض |
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) =>
{
// Bound to the open session's page dimensions
var manager = viewer.GetAnnotationManager(token);
var pageCount = viewer.GetPageCount(token);
// One stamp per page
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));
// Load into the session — the widget fetches them via AnnLoad and the
// renderer burns them into image/PDF exports.
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 of all pages with annotations rendered onto them
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");
});
// Or a ZIP of per-page PNGs
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 للصورة يقدمه المستخدم وتحكم فيه لتجنب تزوير طلبات الخادم.
- تُطبق التصديرات نفس قرار الترخيص/العلامة المائية المخصصة كما في عرض الصفحات على الشاشة.
- الأحمال الكبيرة للخط الحر والتصديرات عالية الدقة تزيد من استهلاك الذاكرة؛ اختبر المستندات والقيم التكبيرية الواقعية.
استكشاف الأخطاء وإصلاحها
| العَرَض | الفحص |
|---|---|
| شريط الـ Ribbon مفقود | قدرة Annotation وعلامات CSS/Script الأربعة للتعليقات |
| استدعاء الحفظ يُبلغ عن خطأ | انتهاء صلاحية الرمز/الجلسة وإعداد BasePath للطبقة الوسيطة |
| تعليقات C# لا تظهر | ترقيم الصفحات يبدأ من الواحد والبيانات تم تحميلها إلى الرمز النشط |
| صورة التعليق تظهر على الشاشة لكنها لا تظهر في التصدير | يستطيع الخادم الوصول إلى عنوان URL للصورة أثناء الدمج |
| المستند المعاد فتحه لا يحتوي على تعليقات | احفظ XML/البيانات خارج جلسة العارض، ثم حمّلها إلى الرمز الجديد |
هل كانت هذه الصفحة مفيدة؟