mirror of
https://github.com/xiaoqidun/ofdgo.git
synced 2026-10-29 17:27:08 +08:00
This commit is contained in:
1 parent
237487b53c
commit
0034e0edbd
11 files changed
+234
-52
No files matched your search
+31
-31
@@ -18,6 +18,7 @@
|
||||
<div class="tool-group">
|
||||
<button id="ofdButton" class="icon-button" type="button" title="打开" aria-label="打开" aria-keyshortcuts="Control+O Meta+O"><span class="open-icon" aria-hidden="true"></span></button>
|
||||
<button id="newButton" class="icon-button" type="button" title="新建" aria-label="新建文档"><span class="new-icon" aria-hidden="true"></span></button>
|
||||
<button id="editButton" class="icon-button" type="button" title="编辑文档" aria-label="编辑文档" aria-pressed="false" disabled><span class="edit-icon" aria-hidden="true"></span></button>
|
||||
<button id="togglePagesButton" class="icon-button" type="button" title="页面栏" aria-label="页面栏" aria-pressed="true">☰</button>
|
||||
<button id="toggleMetaButton" class="icon-button" type="button" title="信息栏" aria-label="信息栏" aria-pressed="true">ⓘ</button>
|
||||
</div>
|
||||
@@ -43,7 +44,6 @@
|
||||
<button id="annotationButton" class="button" type="button" data-short="注" title="关闭注解" aria-label="关闭注解" aria-pressed="true">注解</button>
|
||||
</div>
|
||||
<div class="tool-group">
|
||||
<button id="editButton" class="button" type="button" data-short="编" title="编辑文档" aria-label="编辑文档" aria-pressed="false" disabled>编辑</button>
|
||||
<select id="exportFormat" class="format-select" title="导出格式" aria-label="导出格式" disabled></select>
|
||||
<select id="imageDPI" class="format-select dpi-select" title="图片 DPI" aria-label="图片 DPI" disabled>
|
||||
<option value="96">96</option>
|
||||
@@ -91,28 +91,13 @@
|
||||
</select>
|
||||
<span>对象</span>
|
||||
</div>
|
||||
<div class="editor-group editor-transform">
|
||||
<select id="objectRotate" class="order-select" aria-label="对象旋转" disabled>
|
||||
<option value="" hidden>旋转</option>
|
||||
<option value="90">右转90°</option>
|
||||
<option value="-90">左转90°</option>
|
||||
</select>
|
||||
<select id="objectFlip" class="order-select" aria-label="对象翻转" disabled>
|
||||
<option value="" hidden>翻转</option>
|
||||
<option value="horizontal">水平</option>
|
||||
<option value="vertical">垂直</option>
|
||||
</select>
|
||||
<span>变换</span>
|
||||
</div>
|
||||
<div class="editor-group editor-image">
|
||||
<select id="imageFit" aria-label="图片适应方式" disabled>
|
||||
<option value="" hidden>缩放</option>
|
||||
<option value="contain">适应</option>
|
||||
<option value="cover">填充</option>
|
||||
</select>
|
||||
<button id="cropImageButton" class="button" type="button" aria-label="裁剪图片" aria-pressed="false" disabled>裁剪</button>
|
||||
<button id="resetCropButton" class="button" type="button" aria-label="还原图片" disabled>还原</button>
|
||||
<span>图片</span>
|
||||
<div class="editor-group">
|
||||
<button id="insertTextButton" class="button" type="button" aria-label="添加文字" aria-pressed="false">文字</button>
|
||||
<button id="insertImageButton" class="button" type="button" aria-label="添加图片">图片</button>
|
||||
<button id="drawLineButton" class="button" type="button" aria-label="绘制直线" aria-pressed="false">直线</button>
|
||||
<button id="drawRectangleButton" class="button" type="button" aria-label="绘制矩形" aria-pressed="false">矩形</button>
|
||||
<button id="drawEllipseButton" class="button" type="button" aria-label="绘制椭圆" aria-pressed="false">椭圆</button>
|
||||
<span>插入</span>
|
||||
</div>
|
||||
<div class="editor-group">
|
||||
<div class="text-font"><select id="textFont" aria-label="字体" title="字体" disabled></select><button id="textFontAdd" class="icon-button" type="button" title="添加字体" aria-label="添加字体">+</button></div>
|
||||
@@ -133,20 +118,35 @@
|
||||
<label class="editor-field"><span>字距</span><span class="editor-number"><input id="textSpacing" type="number" step="any" placeholder="0" aria-label="字距" title="字距" disabled><span>pt</span></span></label>
|
||||
<span>段落</span>
|
||||
</div>
|
||||
<div class="editor-group">
|
||||
<button id="insertTextButton" class="button" type="button" aria-label="添加文字" aria-pressed="false">文字</button>
|
||||
<button id="insertImageButton" class="button" type="button" aria-label="添加图片">图片</button>
|
||||
<button id="drawLineButton" class="button" type="button" aria-label="绘制直线" aria-pressed="false">直线</button>
|
||||
<button id="drawRectangleButton" class="button" type="button" aria-label="绘制矩形" aria-pressed="false">矩形</button>
|
||||
<button id="drawEllipseButton" class="button" type="button" aria-label="绘制椭圆" aria-pressed="false">椭圆</button>
|
||||
<span>插入</span>
|
||||
</div>
|
||||
<div class="editor-group">
|
||||
<div class="shape-paint"><label><input id="shapeFill" type="checkbox">填充</label><input id="shapeFillColor" class="color-input" type="color" value="#dcefeb" aria-label="填充颜色" title="填充颜色"></div>
|
||||
<div class="shape-paint"><label><input id="shapeStroke" type="checkbox" checked>描边</label><input id="shapeStrokeColor" class="color-input" type="color" value="#000000" aria-label="描边颜色" title="描边颜色"></div>
|
||||
<label class="editor-field"><span>线宽</span><span class="editor-number"><input id="shapeWidth" type="number" value="1" min="0" step="any" required aria-label="线宽" title="线宽"><span>pt</span></span></label>
|
||||
<span>图形</span>
|
||||
</div>
|
||||
<div class="editor-group editor-image">
|
||||
<select id="imageFit" aria-label="图片适应方式" disabled>
|
||||
<option value="" hidden>缩放</option>
|
||||
<option value="contain">适应</option>
|
||||
<option value="cover">填充</option>
|
||||
</select>
|
||||
<button id="cropImageButton" class="button" type="button" aria-label="裁剪图片" aria-pressed="false" disabled>裁剪</button>
|
||||
<button id="resetCropButton" class="button" type="button" aria-label="还原图片" disabled>还原</button>
|
||||
<span>图片</span>
|
||||
</div>
|
||||
<div class="editor-group editor-transform">
|
||||
<select id="objectRotate" class="order-select" aria-label="对象旋转" disabled>
|
||||
<option value="" hidden>旋转</option>
|
||||
<option value="90">右转90°</option>
|
||||
<option value="-90">左转90°</option>
|
||||
</select>
|
||||
<select id="objectFlip" class="order-select" aria-label="对象翻转" disabled>
|
||||
<option value="" hidden>翻转</option>
|
||||
<option value="horizontal">水平</option>
|
||||
<option value="vertical">垂直</option>
|
||||
</select>
|
||||
<span>变换</span>
|
||||
</div>
|
||||
<div class="editor-group">
|
||||
<button id="addPageButton" class="button" type="button" aria-label="新增页面">新增</button>
|
||||
<button id="copyPageButton" class="button" type="button" aria-label="复制页面">复制</button>
|
||||
|
||||
@@ -374,6 +374,34 @@ button:not(:disabled):hover {
|
||||
transform: translate(-50%, -50%) rotate(90deg);
|
||||
}
|
||||
|
||||
.edit-icon {
|
||||
position: relative;
|
||||
width: 15px;
|
||||
height: 15px;
|
||||
transform: rotate(-45deg);
|
||||
}
|
||||
|
||||
.edit-icon::before {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: 4px;
|
||||
width: 9px;
|
||||
height: 3px;
|
||||
border: 1px solid currentColor;
|
||||
content: "";
|
||||
}
|
||||
|
||||
.edit-icon::after {
|
||||
position: absolute;
|
||||
top: 5px;
|
||||
left: 0;
|
||||
width: 4px;
|
||||
height: 5px;
|
||||
background: currentColor;
|
||||
clip-path: polygon(0 50%, 100% 0, 100% 100%);
|
||||
content: "";
|
||||
}
|
||||
|
||||
.toolbar-space {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
@@ -1305,6 +1333,10 @@ button.outline-link:hover {
|
||||
outline: calc(1px / var(--surface-scale)) solid var(--accent);
|
||||
}
|
||||
|
||||
.edit-object.read-only {
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.edit-line::before {
|
||||
position: absolute;
|
||||
inset: calc(-4px / var(--surface-scale));
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { CanvasEditor, canEditObject } from "./ofdgo_edit.js";
|
||||
import { CanvasEditor, canEditObject, objectEditReason } from "./ofdgo_edit.js";
|
||||
import { FontManager } from "./ofdgo_font.js";
|
||||
|
||||
const MM_TO_PX = 96 / 25.4;
|
||||
@@ -250,7 +250,14 @@ const canvasEditor = new CanvasEditor(el.viewerPanel, {
|
||||
busy: () => document.body.hasAttribute("aria-busy"),
|
||||
rotation: () => state.rotation,
|
||||
canInsert: (index) => pageCan("insert", index),
|
||||
onSelect: updateObjectControls,
|
||||
onSelect: (item, previous) => {
|
||||
updateObjectControls(item);
|
||||
const reason = objectEditReason(item), previousReason = objectEditReason(previous);
|
||||
if (state.editing && state.doc && !document.body.hasAttribute("aria-busy")
|
||||
&& (reason || previousReason && el.statusText.textContent === previousReason)) {
|
||||
setStatus(reason || pageStatus(state.pageIndex, state.doc.pageCount));
|
||||
}
|
||||
},
|
||||
onTransform: (item, change) => changeDocument(item.items ? "ofdgoTransformObjects" : "ofdgoTransformObject", item,
|
||||
change.x + item.x * (1 - change.scale), change.y + item.y * (1 - change.scale), change.scale),
|
||||
onReshape: (item, box) => changeDocument("ofdgoReshapeObject", item, box.x, box.y, box.width, box.height),
|
||||
|
||||
@@ -122,6 +122,22 @@ export function canEditObject(item, capability) {
|
||||
return Boolean(item) && (item.items || [item]).every(object => Boolean(object.capabilities?.[capability]));
|
||||
}
|
||||
|
||||
export function objectEditReason(item) {
|
||||
const reasons = (item?.items || (item ? [item] : [])).map(object => {
|
||||
const reason = object.capabilities?.reason || "";
|
||||
if (!reason) return "";
|
||||
let message = "对象特性暂不支持";
|
||||
if (reason.includes("embedded font")) message = "缺少内嵌字体";
|
||||
else if (reason.includes("does not contain")) message = "字体缺少所需文字";
|
||||
else if (reason.includes("color") || reason.includes("RGB")) message = "颜色样式暂不支持";
|
||||
else if (reason.includes("draw parameter")) message = "绘制参数暂不支持";
|
||||
else if (reason.includes("layer")) message = "图层特性暂不支持";
|
||||
else if (reason.includes("invalid")) message = "对象数据异常";
|
||||
return `${object.capabilities.transform ? "部分操作受限" : "暂不可编辑"}:${message}`;
|
||||
});
|
||||
return [...new Set(reasons.filter(Boolean))].join(";");
|
||||
}
|
||||
|
||||
export class CanvasEditor {
|
||||
constructor(viewer, options) {
|
||||
this.viewer = viewer;
|
||||
@@ -182,6 +198,8 @@ export class CanvasEditor {
|
||||
for (const object of page.objects) {
|
||||
const node = document.createElement("div");
|
||||
node.className = "edit-object";
|
||||
node.classList.toggle("read-only", !canEditObject(object, "transform"));
|
||||
node.title = objectEditReason(object);
|
||||
if (object.shape === "line") {
|
||||
node.classList.add("edit-line");
|
||||
}
|
||||
@@ -269,6 +287,7 @@ export class CanvasEditor {
|
||||
}
|
||||
|
||||
setSelection(items) {
|
||||
const previous = this.selected;
|
||||
if (this.crop && (items.length !== 1 || items[0] !== this.crop.item)) this.closeCrop();
|
||||
if (this.selected?.items) this.selected.node.remove();
|
||||
for (const item of this.items()) {
|
||||
@@ -296,7 +315,7 @@ export class CanvasEditor {
|
||||
item.node.classList.toggle("multi-selected", items.length > 1);
|
||||
item.node.setAttribute("aria-pressed", "true");
|
||||
}
|
||||
this.options.onSelect(this.selected);
|
||||
this.options.onSelect(this.selected, previous);
|
||||
}
|
||||
|
||||
select(item, add = false) {
|
||||
|
||||
Reference in new issue
Block a user