הערות
הוסף תמיכת הערות לצופה
הערות ב‑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">
<!-- בקרות הצופה, כולל הכפתור הפותח Annotation -->
</nav>
<div id="annBarMount"></div>
<div id="divDocViewer"><div id="div_ctlDoc"></div></div>חבילת ההערות מייצרת את ה‑Ribbon DOM בתוך 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), השומר אותו במפגש המסמך לכל עמוד. טעינה (AnnLoad) מתבצעת אוטומטית כאשר עמוד עם הערות מוצג. ארבעת הקריאות 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 הם קריאות חוזרות אופציונליות של המארח. האובייקט endpoints יכול בנוסף לספק exportPdf, exportPng, imageUpload, ו‑imageList; בקרות ללא נקודת קצה מוגדרת נשארות מוסתרות. עבור רצף האתחול המשולב של Viewer, Search, ו‑Annotation, ראה התחלה מהירה(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 ו‑
// renderer שורף אותם לתוך ייצואי תמונה/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 של 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 כאשר נדרש קובץ משטחים.
- סגור את מושב המסמך.
אל תשתמש באסימון הצופה האופקי כמזהה קבוע של אנוטציה. חבר את נתוני האנוטציה השמורים למזהי המסמך והגרסה שלך.
הערות אבטחה והצגה
- בקשות אנוטציה משתמשות באותה אבטחת session/token כמו בקשות דף.
- כתובת URL יחסית של
ImageAnnotationנפתרת מה‑host של הבקשה וחייבת להיות נגישה לשרת בזמן הבערה. - יש לאמת ולשלוט בכל כתובת URL של תמונה שמסופקת על‑ידי המשתמש כדי למנוע זיוף בקשות בצד השרת.
- הייצוא מפעיל את אותה החלטת רישיון/סימן מים מותאם כמו הצגת דף על המסך.
- מטענים חופשיים גדולים וייצוא ברזולוציה גבוהה מגדילים את השימוש בזיכרון; יש לבדוק מסמכים וערכי זום ריאליים.
פתרון בעיות
| תסמין | בדיקה |
|---|---|
| רצועת ההערות חסרה | יכולת Annotation והארבעה דגלים של CSS/script של ההערות |
| ה‑callback של השמירה מדווח על שגיאה | פג תוקף של Token/session וה‑middleware BasePath |
| ההערות של C# אינן מופיעות | מספור העמודים מתחיל מ‑1 והנתונים נטענו לטוקן הפעיל |
| הערת תמונה מופיעה על המסך אך לא בייצוא | השרת יכול לגשת ל‑URL של התמונה בזמן הבערה |
| מסמך שנפתח מחדש אינו מכיל הערות | שמור XML/נתונים מחוץ למפגש הצופה, ואז טען אותם לטוקן החדש |
האם דף זה היה מועיל?