הערות
הוסף תמיכת הערות לצופה
הערות ב‑Doconut פועלות בשני כיוונים: משתמשים מציירים אותן בווידג'ט של הדפדפן והשרת שומר אותן לכל עמוד, או שהקוד שלך בונה אותן תכנותית ונטען אותן למפגש פתוח. בכל מקרה הן מוצגות על העמודים וניתן לשרוף אותן לייצוא PDF/PNG.
תמיכת ההערות מוגבלת על‑ידי יכולת הרישיון Annotation (ניתנת אוטומטית תחת רישיון Temporary פעיל).
הפעלת ממשק המשתמש של ההערות
הערה היא מודול של Viewer, לא סרגל נפרד. על כל העמוד לכלול
את משאבי Viewer, סרגל הכלים של Viewer, הרכבת Viewer, וה‑objViewer שהותחל; לאחר מכן
ה‑Annotation Ribbon מותקן ומצורף לאותו מופע.
הפץ את חבילות ההערות יחד עם חבילות הצופה — הן מוגבלות ברישיון, ולכן התגיות מופיעות רק כאשר היכולת זמינה:
@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>חבילת ההערות מייצרת את ה‑DOM של ה‑Ribbon בתוך annBarMount; אין צורך
להעתיק את הכפתורים או את מרקאפ הדיאלוג שלה. אתחל תחילה את docViewer, ואז צור את ה‑Ribbon
רק כאשר השרת מאשר שה‑Annotation מורשה:
<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), אשר שומר אותם
ב‑session של המסמך לכל עמוד. טעינה (AnnLoad) מתבצעת אוטומטית כאשר עמוד עם
הערות מוצג. ארבעת ה‑callback onAnn* משמרים את ה‑Ribbon מסונכרן עם
מחזור החיים של הצופה.
פתח וסגור אותו מכל סרגל Viewer שבבעלות המארח:
annBar.open();
annBar.close();API הציבורי של Ribbon הוא:
| מתודה | מטרה |
|---|---|
attach(objViewer) | מחבר את ה‑Ribbon לצופה שהותחל; נדרש פעם אחת |
open() / close() | נכנס או יוצא ממצב עריכת הערות |
reset() | מחזיר את ה‑Ribbon למצב סגור, ללא עריכה |
isOpen() / annotating() | קורא את מצב ה‑Ribbon / מצב עריכת ההערות של הצופה |
reopenEditable() | טוען מחדש את ההערות של העמוד הנוכחי כאובייקטים ניתנים לעריכה |
updateActionState() | מרענן את זמינות הבקרות שמירת/מחיקה לאחר שינויי המארח |
headerSlot() | מקבל את משבצת ההרחבה האופציונלית בכותרת לבקרות שבבעלות המארח |
onStatus, onToast, onLayout, onEditStart, ו‑onEditEnd הם callback‑ים אופציונליים של המארח. האובייקט endpoints יכול בנוסף לספק exportPdf, exportPng,
imageUpload, ו‑imageList; בקרות ללא נקודת קצה מוגדרת נשארות מוסתרות.
עבור רצף האתחול המשולב של Viewer, Search, ו‑Annotation, ראה
התחלה מהירה.
חבילת ההערות מוסיפה את כלי המחבר בדפדפן, אך הנתונים עדיין שייכים ל‑session של המסמך בצד השרת המזוהה על‑ידי הטוקן. פתיחה מחדש של המקור יוצרת session חדש; שמור את ה‑XML או את מעטפת ההערות המקודדת באפליקציה שלך אם ההערות חייבות לשרוד מעבר לחיי ה‑session.
בניית הערות ב‑C#
קבל מנהל הקשור ל‑session הפתוח, הוסף הערות, וטען אותן (עם 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. כתובת יחסית נפתרת ביחס למארח הבקשה כאשר מוסיפים את ההערה (רק שליפת התמונה מתרחשת בזמן השריפה) — היא חייבת להיות נגישה מהשרת (למשל קובץ תחת wwwroot המוגש על‑ידי UseStaticFiles) |
API של AnnotationManager
| חבר | מטרה |
|---|---|
Add(BaseAnnotation) | מוסיף הערה לתור |
GetAnnotations() / GetAnnotations(int page) | מציג מה המנהל מחזיק |
ClearAnnotations() / ClearAnnotations(int page) | מוחק הכל / לפי עמוד |
GetAnnotationData() / GetAnnotationData(int page) | מחרוזת נתוני ההערה המקודדת — מעטפת Base64 (מה שהווידג'ט צורך) |
GetAnnotationXml() | צורת XML |
Viewer משקף את פעולות הטעינה/קריאה מול session: 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 או נתונים מקודדים שנשמרו קודם לכן לתוך הטוקן.
- אפשר לווידג'ט לקרוא ולערוך את ההערות ב‑session.
- קבל XML עם
GetAnnotationXML(token)כאשר האפליקציה שלך מחליטה לשמור. - ייצא PDF/PNG כאשר נדרש קובץ משטחים.
- סגור את session של המסמך.
אל תשתמש בטוקן הצופה השקוף כמזהה קבוע של הערה. קשר את נתוני ההערה השמורים למזהי המסמך והגרסה שלך.
אבטחה והערות רינדור
- בקשות הערה משתמשות באותה אבטחת session/טוקן כמו בקשות עמוד.
- כתובת URL יחסית של
ImageAnnotationנפתרת ממארח הבקשה וחייבת להיות נגישה לשרת בזמן השריפה. - אמת ושלוט בכל כתובת URL של תמונה שמסופקת על‑ידי משתמש כדי למנוע זיוף בקשות צד שרת.
- ייצוא מחיל את אותה החלטת רישיון/סימן מים מותאם כמו רינדור עמוד על המסך.
- עומסי freehand גדולים וייצוא ברזולוציה גבוהה מגדילים שימוש בזיכרון; בדוק מסמכים וערכי זום ריאליים.
פתרון בעיות
| סימפטום | בדיקה |
|---|---|
| חוסר בריבון ההערות | יכולת Annotation והדגלים ארבעת של CSS/Script של ההערות |
| קריאת שגיאה במשתיקת שמירה | פקיעת טוקן/session והגדרת BasePath במידלוור |
| הערות C# אינן מופיעות | מספור העמודים הוא מבוסס‑אחד והנתונים נטענו לטוקן הפעיל |
| הערת תמונה מוצגת על המסך אך לא בייצוא | השרת יכול להגיע לכתובת ה‑URL של התמונה בזמן השריפה |
| מסמך שנפתח מחדש ללא הערות | שמור XML/נתונים מחוץ ל‑session של הצופה, ואז טען אותם לטוקן החדש |
האם דף זה היה מועיל?