הערות

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

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

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

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

הערה היא מודול של 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">
    <!-- 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 מורשה:

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), אשר שומר אותם ב‑session של המסמך לכל עמוד. טעינה (AnnLoad) מתבצעת אוטומטית כאשר עמוד עם הערות מוצג. ארבעת ה‑callback 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 הם callback‑ים אופציונליים של המארח. האובייקט endpoints יכול בנוסף לספק exportPdf, exportPng, imageUpload, ו‑imageList; בקרות ללא נקודת קצה מוגדרת נשארות מוסתרות. עבור רצף האתחול המשולב של Viewer, Search, ו‑Annotation, ראה התחלה מהירה.

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

בניית הערות ב‑C#

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

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

ייצוא עם הערות משולבות

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

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

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

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

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

אבטחה והערות רינדור

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

פתרון בעיות

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

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