Σχόλια
Προσθήκη υποστήριξης σχολίων στον προβολέα
Τα Σχόλια στο Doconut λειτουργούν σε δύο κατευθύνσεις: οι χρήστες τα σχεδιάζουν στο widget του προγράμματος περιήγησης και ο διακομιστής τα αποθηκεύει ανά σελίδα, ή ο κώδικάς σας τα δημιουργεί προγραμματιστικά και τα φορτώνει σε μια ανοιχτή συνεδρία. Σε κάθε περίπτωση εμφανίζονται στις σελίδες και μπορούν να ενσωματωθούν σε εξαγωγές PDF/PNG.
Η υποστήριξη Σχολίων ελέγχεται από τη δυνατότητα άδειας Annotation (χάρη αυτόματα υπό ενεργή προσωρινή άδεια).
Ενεργοποίηση του UI σχολίων
Το Σχόλιο είναι ένα module του 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, συμπεριλαμβανομένου του κουμπιού που ανοίγει το 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: '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 στέλνει δεδομένα μέσω του middleware (AnnSave), το οποίο τα αποθηκεύει στη συνεδρία εγγράφου ανά σελίδα. Η φόρτωση (AnnLoad) γίνεται αυτόματα όταν μια σελίδα με σχόλια αποδίδεται. Τα τέσσερα callbacks onAnn* διατηρούν το Ribbon συγχρονισμένο με τον κύκλο ζωής του viewer.
Ανοίξτε και κλείστε το από οποιαδήποτε γραμμή εργαλείων 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 είναι προαιρετικά 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) =>
{
// Συνδεδεμένο με διαστάσεις σελίδας της ανοιχτής συνεδρίας
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));
// Φόρτωση στη συνεδρία — το widget τα ανακτά μέσω 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) |
Το API του AnnotationManager
| Μέλος | Σκοπός |
|---|---|
Add(BaseAnnotation) | Προσθήκη μιας σημείωσης στην ουρά |
GetAnnotations() / GetAnnotations(int page) | Επισκόπηση των σημειώσεων που διατηρεί ο διαχειριστής |
ClearAnnotations() / ClearAnnotations(int page) | Καθαρισμός όλων ή ανά σελίδα |
GetAnnotationData() / GetAnnotationData(int page) | Κωδικοποιημένη συμβολοσειρά δεδομένων σημειώσεων — ένα Base64 envelope (αυτό που καταναλώνει το widget) |
GetAnnotationXml() | Μορφή XML |
Ο Viewer αντικατοπτρίζει τις λειτουργίες φόρτωσης/ανάγνωσης έναντι μιας συνεδρίας: LoadAnnotationData(token, manager) ή LoadAnnotationData(token, encodedData) (το Base64 envelope από το 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 με PNG ανά σελίδα
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 όταν απαιτείται ένα επίπεδο παραδοτέο.
- Κλείστε τη συνεδρία του εγγράφου.
Μην χρησιμοποιείτε το αδιαφανές token του viewer ως μόνιμο αναγνωριστικό σημείωσης. Συνδέστε τα αποθηκευμένα δεδομένα σημειώσεων με τα δικά σας αναγνωριστικά εγγράφου και έκδοσης.
Σημειώσεις ασφαλείας και απόδοσης
- Τα αιτήματα σχολιασμού χρησιμοποιούν την ίδια ασφάλεια συνεδρίας/διακριτικού όπως τα αιτήματα σελίδας.
- Ένα σχετικό
ImageAnnotationURL επιλύεται από τον κεντρικό υπολογιστή του αιτήματος και πρέπει να παραμένει προσβάσιμο στον διακομιστή κατά τη διαδικασία δημιουργίας. - Επικυρώστε και ελέγξτε οποιοδήποτε URL εικόνας που παρέχεται από τον χρήστη για να αποφύγετε την πλαστογραφία αιτημάτων από τον διακομιστή.
- Οι εξαγωγές εφαρμόζουν την ίδια απόφαση άδειας/προσαρμοσμένου υδατογραφήματος όπως η απόδοση σελίδας στην οθόνη.
- Μεγάλα φορτία ελεύθερης σχεδίασης και εξαγωγές υψηλής ανάλυσης αυξάνουν τη χρήση μνήμης· δοκιμάστε ρεαλιστικά έγγραφα και τιμές ζουμ.
Επίλυση προβλημάτων
| Σύμπτωμα | Έλεγχος |
|---|---|
| Το λουρί σχολιασμού λείπει | Annotation δυνατότητα και οι τέσσερις σημαίες CSS/script σχολιασμού |
| Η κλήση επιστροφής αποθήκευσης αναφέρει σφάλμα | Λήξη διακριτικού/συνεδρίας και middleware BasePath |
| Οι σχολιασμοί C# δεν εμφανίζονται | Η αρίθμηση σελίδων είναι με βάση το 1 και τα δεδομένα φορτώθηκαν στο ενεργό διακριτικό |
| Η εικόνα σχολιασμού εμφανίζεται στην οθόνη αλλά όχι στην εξαγωγή | Ο διακομιστής μπορεί να φτάσει στο URL της εικόνας κατά τη διαδικασία δημιουργίας |
| Το ξαναανοιγμένο έγγραφο δεν έχει σχολιασμούς | Διατηρήστε το XML/δεδομένα εκτός της συνεδρίας του προβολέα, στη συνέχεια φορτώστε τα στο νέο διακριτικό |
Ήταν αυτή η σελίδα χρήσιμη;