Σημειώσεις
Προσθέστε υποστήριξη σημειώσεων στον προβολέα
Οι σημειώσεις στο Doconut λειτουργούν σε δύο κατευθύνσεις: οι χρήστες τις σχεδιάζουν στο widget του προγράμματος περιήγησης και ο διακομιστής τις αποθηκεύει ανά σελίδα, ή ο κώδικάς σας τις δημιουργεί προγραμματιστικά και τις φορτώνει σε μια ανοιχτή συνεδρία. Σε κάθε περίπτωση εμφανίζονται στις σελίδες και μπορούν να ενσωματωθούν σε εξαγωγές PDF/PNG.
Η υποστήριξη σημειώσεων ελέγχεται από τη δυνατότητα άδειας Annotation (χορηγείται αυτόματα υπό ενεργή προσωρινή άδεια).
Ενεργοποίηση του UI σημειώσεων
Η σημείωση είναι μια μονάδα του Viewer, όχι μια αυτόνομη γραμμή εργαλείων. Η πλήρης σελίδα πρέπει να περιλαμβάνει τους πόρους του Viewer, τη γραμμή εργαλείων του Viewer, το mount του Viewer και το αρχικοποιημένο objViewer; η Ribbon των Σημειώσεων στη συνέχεια τοποθετείται και συνδέεται με το ίδιο παράδειγμα.
Εκδώστε τα πακέτα σημειώσεων μαζί με τα πακέτα του viewer — είναι ελεγχόμενα από άδεια, έτσι οι ετικέτες εμφανίζονται μόνο όταν η δυνατότητα είναι διαθέσιμη:
@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 ορατή στο markup:
<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; δεν χρειάζεται να αντιγράψετε τα κουμπιά ή το markup του διαλόγου. Αρχικοποιήστε πρώτα το docViewer, στη συνέχεια δημιουργήστε τη Ribbon μόνο όταν ο διακομιστής επιβεβαιώσει ότι η Σημείωση είναι αδειοδοτημένη:
<script>
let annBar = null;
let currentToken = '';
const objViewer = $('#div_ctlDoc').docViewer({
BasePath: '/',
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 αποστέλλει δεδομένα μέσω του middleware (AnnSave), το οποίο τα αποθηκεύει στη συνεδρία εγγράφου ανά σελίδα. Η φόρτωση (AnnLoad) γίνεται αυτόματα όταν μια σελίδα με σημειώσεις αποδίδεται. Τα τέσσερα callbacks onAnn* διατηρούν τη Ribbon συγχρονισμένη με τον κύκλο ζωής του viewer.
Ανοίξτε και κλείστε τη από οποιαδήποτε γραμμή εργαλείων Viewer που ανήκει στον κεντρικό:
annBar.open();
annBar.close();Το δημόσιο API της Ribbon είναι:
| Μέθοδος | Σκοπός |
|---|---|
attach(objViewer) | Συνδέει τη Ribbon με τον αρχικοποιημένο viewer· απαιτείται μία φορά |
open() / close() | Ξεκινά ή τερματίζει την επεξεργασία σημειώσεων |
reset() | Επαναφέρει τη Ribbon στην κλειστή, μη-επεξεργαστική κατάσταση |
isOpen() / annotating() | Διαβάζει την κατάσταση της Ribbon / την κατάσταση επεξεργασίας σημειώσεων του viewer |
reopenEditable() | Φορτώνει ξανά τις σημειώσεις της τρέχουσας σελίδας ως επεξεργάσιμα αντικείμενα |
updateActionState() | Ανανεώνει τη διαθεσιμότητα των ελέγχων αποθήκευσης/διαγραφής μετά από αλλαγές του κεντρικού |
headerSlot() | Λαμβάνει το προαιρετικό slot επέκτασης κεφαλίδας για ελέγχους που ανήκουν στον κεντρικό |
onStatus, onToast, onLayout, onEditStart και onEditEnd είναι προαιρετικά callbacks του κεντρικού. Το αντικείμενο endpoints μπορεί επιπλέον να παρέχει exportPdf, exportPng, imageUpload και imageList; τα στοιχεία χωρίς ρυθμισμένο endpoint παραμένουν κρυφά. Για τη σειρά εκκίνησης του συνδυασμένου Viewer, Search και Annotation, δείτε το Γρήγορη Έναρξη.
Το πακέτο σημειώσεων προσθέτει τα εργαλεία δημιουργίας του προγράμματος περιήγησης, αλλά τα δεδομένα ανήκουν ακόμη στη συνεδρία εγγράφου στην πλευρά του διακομιστή που προσδιορίζεται από το token. Η επαναφορά του πηγής δημιουργεί νέα συνεδρία· αποθηκεύστε το 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) |
Το API του AnnotationManager
| Μέλος | Σκοπός |
|---|---|
Add(BaseAnnotation) | Προσθήκη σχολιασμού στην ουρά |
GetAnnotations() / GetAnnotations(int page) | Επισκόπηση του τι κρατά ο διαχειριστής |
ClearAnnotations() / ClearAnnotations(int page) | Αφαίρεση όλων / ανά σελίδα |
GetAnnotationData() / GetAnnotationData(int page) | Κωδικοποιημένη συμβολοσειρά δεδομένων σχολιασμού — ένα Base64 περιτύλιγμα (αυτό που καταναλώνει το widget) |
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");
});Οι εξαγωγές χρησιμοποιούν τον ίδιο μηχανισμό καψίματος όπως η απόδοση στην οθόνη, έτσι ό,τι βλέπουν οι χρήστες είναι ό,τι περιέχει το αρχείο.
Ροή εργασίας διατήρησης
- Ανοίξτε το έγγραφο και λάβετε το token του.
- Φορτώστε το προηγουμένως αποθηκευμένο XML ή κωδικοποιημένα δεδομένα σε αυτό το token.
- Αφήστε το widget να διαβάσει και να επεξεργαστεί τους σχολιασμούς της συνεδρίας.
- Ανακτήστε το XML με
GetAnnotationXML(token)όταν η εφαρμογή σας αποφασίσει να το διατηρήσει. - Εξάγετε PDF/PNG όταν απαιτείται ένα επίπεδο (flattened) παραδοτέο.
- Κλείστε τη συνεδρία του εγγράφου.
Μην χρησιμοποιείτε το αδιαφανές token του viewer ως μόνιμο αναγνωριστικό σχολιασμού. Συσχετίστε τα διατηρημένα δεδομένα σχολιασμού με τα δικά σας αναγνωριστικά εγγράφου και έκδοσης.
Σημειώσεις ασφαλείας και απόδοσης
- Τα αιτήματα σχολιασμού χρησιμοποιούν την ίδια ασφάλεια συνεδρίας/διακριτικού όπως τα αιτήματα σελίδας.
- Μια σχετική
ImageAnnotationURL επιλύεται από τον κεντρικό υπολογιστή του αιτήματος και πρέπει να παραμένει προσβάσιμη από τον διακομιστή κατά τη διαδικασία δημιουργίας. - Επικυρώστε και ελέγξτε οποιαδήποτε URL εικόνας που παρέχεται από τον χρήστη ώστε να αποφύγετε την πλαστογραφία αιτημάτων στην πλευρά του διακομιστή.
- Οι εξαγωγές εφαρμόζουν την ίδια απόφαση άδειας/προσαρμοσμένου υδατογραφήματος όπως η απόδοση σελίδας στην οθόνη.
- Μεγάλα φορτία ελεύθερης σχεδίασης και εξαγωγές υψηλής ανάλυσης αυξάνουν τη χρήση μνήμης· δοκιμάστε ρεαλιστικά έγγραφα και τιμές ζουμ.
Επίλυση προβλημάτων
| Συμπτωμα | Έλεγχος |
|---|---|
| Το κορδέλα σχολιασμού λείπει | Annotation δυνατότητα και οι τέσσερις σημαίες CSS/σκριπτ σχολιασμού |
| Η κλήση επιστροφής αποθήκευσης αναφέρει σφάλμα | Λήξη διακριτικού/συνεδρίας και middleware BasePath |
| Οι σχολιασμοί C# δεν εμφανίζονται | Η αρίθμηση σελίδων είναι με βάση το 1 και τα δεδομένα φορτώθηκαν στο ενεργό διακριτικό |
| Η σχολιασμός εικόνας εμφανίζεται στην οθόνη αλλά όχι στην εξαγωγή | Ο διακομιστής μπορεί να φτάσει στη διεύθυνση URL της εικόνας κατά τη δημιουργία |
| Το ξανανοιγμένο έγγραφο δεν έχει σχολιασμούς | Διατηρήστε XML/δεδομένα εκτός της συνεδρίας του προβολέα, στη συνέχεια φορτώστε τα στο νέο διακριτικό |
Ήταν αυτή η σελίδα χρήσιμη;