הערות

הוספת תמיכת הערות לצופה

הערות ב‑Doconut פועלות בשני כיוונים: משתמשים מציירים אותן בווידג'ט הדפדפן והשרת שומר אותן לכל עמוד, או שהקוד שלכם בונה אותן תכנותית וטוען אותן למפגש פתוח. בכל מקרה הן מוצגות על הדפים וניתן לשלב אותן בייצוא PDF/PNG.

תמיכת ההערות מוגבלת על‑ידי יכולת הרישיון Annotation (ניתנת באופן אוטומטי תחת רישיון זמני פעיל).

הפעלת ממשק המשתמש של ההערות

ההערה היא מודול של Viewer, ולא סרגל כלים נפרד. על העמוד המלא לכלול את משאבי ה‑Viewer, סרגל הכלים של Viewer, הרכבה של Viewer, ואת objViewer שהאותחל; לאחר מכן רצועת ההערות (Annotation Ribbon) מותקנת ומצורפת לאותו מופע.

הפיצו את חבילות ההערות יחד עם חבילות הצופה — הן מוגבלות ברישיון, ולכן התגים מופיעים רק כאשר היכולת זמינה:

html
@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 גלויה בסימון:

html
<nav id="toolbar" aria-label="Document viewer controls">
    <!-- בקרות הצופה, כולל הכפתור הפותח Annotation -->
</nav>
<div id="annBarMount"></div>
<div id="divDocViewer"><div id="div_ctlDoc"></div></div>

חבילת ההערות מייצרת את ה‑DOM של ה‑Ribbon בתוך annBarMount; אין צורך להעתיק את הכפתורים או את סימון הדיאלוג שלה. אתחלו תחילה את docViewer, ולאחר מכן צרו את ה‑Ribbon רק כאשר השרת מאשר שה‑Annotation מורשה:

html
<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 שבבעלות המארח:

javascript
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, ראו את התחלה מהירה.

חבילת ההערות מוסיפה את כלי העריכה בדפדפן, אך הנתונים עדיין שייכים למפגש המסמך בצד השרת המזוהה באמצעות הטוקן. פתיחה מחדש של המקור יוצרת מפגש חדש; שמרו את ה‑XML או את מעטפת ההערות המקודדת באפליקציה שלכם אם יש צורך שההערות ישרדו מעבר לחיי המפגש.

בניית אנוטציות ב‑C#

קבל מנהל הקשור למפגש הפתוח, הוסף אנוטציות, וטען אותן (עם using Doconut.Annotations; לסוגים ו-using System.Drawing; עבור Rectangle/Color):

csharp
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).

ייצוא עם אנוטציות משולבות

csharp
// 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");
});

הייצוא משתמש באותו מנגנון שריפה כמו רינדור על המסך, ולכן מה שהמשתמשים רואים הוא מה שהקובץ מכיל.

זרימת עבודה של שמירה

  1. פתח את המסמך וקבל את האסימון שלו.
  2. טען XML או נתונים מקודדים שנשמרו מראש לתוך האסימון הזה.
  3. אפשר לווידג׳ט לקרוא ולערוך את האנוטציות של המושב.
  4. קבל XML באמצעות GetAnnotationXML(token) כאשר האפליקציה שלך מחליטה לשמור.
  5. ייצא PDF/PNG כאשר נדרש קובץ משטחים.
  6. סגור את מושב המסמך.

אל תשתמש באסימון הצופה האטום כמזהה קבוע של אנוטציה. קשר את נתוני האנוטציה השמורים עם מזהי המסמך והגרסה שלך.

הערות אבטחה והצגה

  • בקשות אנוטציה משתמשות באותה אבטחת session/token כמו בקשות דף.
  • כתובת URL יחסית של ImageAnnotation נפתרת מה‑host של הבקשה וחייבת להישאר נגישה לשרת בזמן הבערה.
  • יש לאמת ולשלוט בכל כתובת URL של תמונה שמסופקת על ידי המשתמש כדי למנוע זיוף בקשות בצד השרת.
  • ייצוא משלים את אותה החלטת רישיון/סימן מים מותאם כמו הצגת דף על המסך.
  • מטענים חופשיים גדולים וייצוא ברזולוציה גבוהה מגבירים את השימוש בזיכרון; יש לבדוק מסמכים ריאליים וערכי זום.

פתרון בעיות

תסמיןבדיקה
סרגל האנוטציה חסריכולת Annotation והארבעה דגלי CSS/סקריפט של אנוטציה
קריאת חזרה של שמירה מדווחת על שגיאהתפוגת Token/session ו‑middleware BasePath
C# אנוטציות אינן מופיעותמספור העמודים הוא מבוסס על 1 והנתונים נטענו לתוך ה‑token הפעיל
האנוטציה של תמונה מופיעה על המסך אך לא בייצואהשרת יכול להגיע ל‑URL של התמונה בזמן הבערה
מסמך שנפתח מחדש אין בו אנוטציותשמור XML/נתונים מחוץ למפגש הצופה, ואז טען אותם לתוך ה‑token החדש

האם דף זה היה מועיל?