mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-30 01:27:26 +08:00
1 parent
07e1ec18e1
commit
82d78feb6b
3 files changed
+49
-22
No files matched your search
@@ -3129,7 +3129,6 @@ audio.page-media {
|
|||||||
|
|
||||||
.annotation-note {
|
.annotation-note {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
z-index: 2;
|
|
||||||
opacity: 0;
|
opacity: 0;
|
||||||
pointer-events: none;
|
pointer-events: none;
|
||||||
width: 22px;
|
width: 22px;
|
||||||
|
|||||||
+20
-10
@@ -10221,8 +10221,9 @@ async function focusPageRegion(region, label, alignment = "nearest") {
|
|||||||
if (label === "注解") {
|
if (label === "注解") {
|
||||||
for (const note of pageShell(pageIndex)?.querySelectorAll(".annotation-note") || []) {
|
for (const note of pageShell(pageIndex)?.querySelectorAll(".annotation-note") || []) {
|
||||||
if (note.dataset.annotationId !== String(region.id)) continue;
|
if (note.dataset.annotationId !== String(region.id)) continue;
|
||||||
|
window.clearTimeout(note.locateTimer);
|
||||||
note.classList.add("located");
|
note.classList.add("located");
|
||||||
window.setTimeout(() => note.classList.remove("located"), 1800);
|
note.locateTimer = window.setTimeout(() => note.classList.remove("located"), 1800);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
setStatus(`已定位${label}(第${region.page}页)`);
|
setStatus(`已定位${label}(第${region.page}页)`);
|
||||||
@@ -10254,20 +10255,30 @@ function highlightPageRegion(region, alignment = "nearest") {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function clearRegionHighlights() {
|
function clearRegionHighlights() {
|
||||||
for (const note of el.svgHost.querySelectorAll(".annotation-note.located")) note.classList.remove("located");
|
for (const note of el.svgHost.querySelectorAll(".annotation-note.located")) {
|
||||||
|
window.clearTimeout(note.locateTimer);
|
||||||
|
note.classList.remove("located");
|
||||||
|
}
|
||||||
for (const mark of el.svgHost.querySelectorAll(".region-highlight")) {
|
for (const mark of el.svgHost.querySelectorAll(".region-highlight")) {
|
||||||
mark.remove();
|
mark.remove();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function mountAnnotationNotes(index, surface, annotations) {
|
function mountAnnotationNotes(index, surface, annotations) {
|
||||||
for (const note of surface.querySelectorAll(".annotation-note")) note.remove();
|
for (const note of surface.querySelectorAll(".annotation-note")) {
|
||||||
|
window.clearTimeout(note.locateTimer);
|
||||||
|
note.remove();
|
||||||
|
}
|
||||||
surface.onpointermove = surface.onpointerleave = null;
|
surface.onpointermove = surface.onpointerleave = null;
|
||||||
if (!state.renderAnnotations) return;
|
if (!state.renderAnnotations) return;
|
||||||
const page = state.doc.pages[index];
|
const page = state.doc.pages[index];
|
||||||
const notes = [];
|
const notes = [];
|
||||||
for (const annotation of annotations || []) {
|
for (const annotation of annotations || []) {
|
||||||
if (!annotation.visible || annotationKind(annotation) === "Link" || annotation.page !== index + 1 || !annotation.remark?.trim()) continue;
|
if (!annotation.visible || annotationKind(annotation) === "Link" || annotation.page !== index + 1 || !annotation.remark?.trim()) continue;
|
||||||
|
const bounds = annotation.bounds;
|
||||||
|
const region = !bounds ? annotation : bounds.W > 0 && bounds.H > 0
|
||||||
|
? {x: bounds.X, y: bounds.Y, width: bounds.W, height: bounds.H, contours: annotation.contours || []}
|
||||||
|
: {x: annotation.x, y: annotation.y, width: 22 / MM_TO_PX, height: 22 / MM_TO_PX, contours: []};
|
||||||
const note = document.createElement("button");
|
const note = document.createElement("button");
|
||||||
note.type = "button";
|
note.type = "button";
|
||||||
note.className = "annotation-note";
|
note.className = "annotation-note";
|
||||||
@@ -10278,8 +10289,8 @@ function mountAnnotationNotes(index, surface, annotations) {
|
|||||||
note.title = "查看注解";
|
note.title = "查看注解";
|
||||||
note.setAttribute("aria-label", "查看注解");
|
note.setAttribute("aria-label", "查看注解");
|
||||||
note.setAttribute("aria-haspopup", "dialog");
|
note.setAttribute("aria-haspopup", "dialog");
|
||||||
note.style.left = `${Math.max(22 / MM_TO_PX, Math.min(page.width, annotation.x + annotation.width)) * MM_TO_PX}px`;
|
note.style.left = `${Math.max(22 / MM_TO_PX, Math.min(page.width, region.x + region.width)) * MM_TO_PX}px`;
|
||||||
note.style.top = `${Math.max(0, Math.min(page.height - 22 / MM_TO_PX, annotation.y)) * MM_TO_PX}px`;
|
note.style.top = `${Math.max(0, Math.min(page.height - 22 / MM_TO_PX, region.y)) * MM_TO_PX}px`;
|
||||||
note.addEventListener("click", () => {
|
note.addEventListener("click", () => {
|
||||||
if (state.editing || document.body.hasAttribute("aria-busy")) return;
|
if (state.editing || document.body.hasAttribute("aria-busy")) return;
|
||||||
el.annotationDetail.replaceChildren();
|
el.annotationDetail.replaceChildren();
|
||||||
@@ -10295,18 +10306,17 @@ function mountAnnotationNotes(index, surface, annotations) {
|
|||||||
el.annotationNote.showModal();
|
el.annotationNote.showModal();
|
||||||
});
|
});
|
||||||
surface.append(note);
|
surface.append(note);
|
||||||
notes.push({note, annotation});
|
notes.push({note, region});
|
||||||
}
|
}
|
||||||
if (!notes.length) return;
|
if (!notes.length) return;
|
||||||
// 从页面监听悬停,不用透明热区拦截正文选择和链接操作。
|
|
||||||
surface.onpointermove = event => {
|
surface.onpointermove = event => {
|
||||||
if (event.pointerType === "touch" || state.editing) return;
|
if (event.pointerType === "touch" || state.editing) return;
|
||||||
const point = pagePoint(event.clientX, event.clientY, surface.getBoundingClientRect(), page, state.rotation);
|
const point = pagePoint(event.clientX, event.clientY, surface.getBoundingClientRect(), page, state.rotation);
|
||||||
const hovered = notes.map(({note, annotation}) => {
|
const overAction = event.target?.closest?.(".page-link, .page-media");
|
||||||
|
const hovered = notes.map(({note, region}) => {
|
||||||
const rect = note.getBoundingClientRect();
|
const rect = note.getBoundingClientRect();
|
||||||
const overNote = event.clientX >= rect.left && event.clientX <= rect.right && event.clientY >= rect.top && event.clientY <= rect.bottom;
|
const overNote = event.clientX >= rect.left && event.clientX <= rect.right && event.clientY >= rect.top && event.clientY <= rect.bottom;
|
||||||
const overRegion = point.x >= annotation.x && point.x <= annotation.x + annotation.width && point.y >= annotation.y && point.y <= annotation.y + annotation.height;
|
return !overAction && (overNote || canvasEditor.contains(region, point));
|
||||||
return overNote || overRegion;
|
|
||||||
});
|
});
|
||||||
notes.forEach(({note}, i) => note.classList.toggle("active", hovered[i]));
|
notes.forEach(({note}, i) => note.classList.toggle("active", hovered[i]));
|
||||||
};
|
};
|
||||||
|
|||||||
+29
-11
@@ -158,16 +158,23 @@ type PageInfo struct {
|
|||||||
|
|
||||||
// PageSVG 页面SVG结果
|
// PageSVG 页面SVG结果
|
||||||
type PageSVG struct {
|
type PageSVG struct {
|
||||||
Index int `json:"index"`
|
Index int `json:"index"`
|
||||||
Number int `json:"number"`
|
Number int `json:"number"`
|
||||||
ID string `json:"id"`
|
ID string `json:"id"`
|
||||||
Width float64 `json:"width"`
|
Width float64 `json:"width"`
|
||||||
Height float64 `json:"height"`
|
Height float64 `json:"height"`
|
||||||
SVG string `json:"svg"`
|
SVG string `json:"svg"`
|
||||||
Links []ofdgo.PageLink `json:"-"`
|
Links []ofdgo.PageLink `json:"-"`
|
||||||
Fonts []ofdgo.SVGFont `json:"-"`
|
Fonts []ofdgo.SVGFont `json:"-"`
|
||||||
Images []ofdgo.SVGImage `json:"-"`
|
Images []ofdgo.SVGImage `json:"-"`
|
||||||
Annotations []ofdgo.AnnotationInfo `json:"annotations,omitempty"`
|
Annotations []AnnotationPreview `json:"annotations,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// AnnotationPreview 注解预览信息及页面坐标中的交互范围
|
||||||
|
type AnnotationPreview struct {
|
||||||
|
ofdgo.AnnotationInfo
|
||||||
|
Bounds ofdgo.Box `json:"bounds"`
|
||||||
|
Contours []ofdgo.ObjectContour `json:"contours,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// ExportFormat 导出格式
|
// ExportFormat 导出格式
|
||||||
@@ -617,10 +624,21 @@ func (s *Session) RenderPage(index int, backend string, dpi float64, raster bool
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return PageSVG{}, err
|
return PageSVG{}, err
|
||||||
}
|
}
|
||||||
annotations, err := s.Reader.AnnotationInfosByIndex(index)
|
infos, err := s.Reader.AnnotationInfosByIndex(index)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return PageSVG{}, err
|
return PageSVG{}, err
|
||||||
}
|
}
|
||||||
|
annotations := make([]AnnotationPreview, len(infos))
|
||||||
|
for i, info := range infos {
|
||||||
|
annotations[i].AnnotationInfo = info
|
||||||
|
if !renderer.RenderAnnotations || !info.Visible || strings.TrimSpace(info.Remark) == "" || info.Type == "Link" || info.Type == "Path" && info.Subtype == "Link" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
bounds, contours, err := renderer.AnnotationGeometry(s.Reader.Annots[page.ID][i])
|
||||||
|
if err == nil {
|
||||||
|
annotations[i].Bounds, annotations[i].Contours = bounds, contours
|
||||||
|
}
|
||||||
|
}
|
||||||
clear(s.svgFonts)
|
clear(s.svgFonts)
|
||||||
for i, font := range resources.Fonts {
|
for i, font := range resources.Fonts {
|
||||||
s.svgFonts[font.Name] = font.Data
|
s.svgFonts[font.Name] = font.Data
|
||||||
|
|||||||
Reference in new issue
Block a user