editor-svg 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.editorconfig +9 -0
- package/.eslintrc +46 -0
- package/.prettierrc +8 -0
- package/AGENTS.md +186 -0
- package/CHANGELOG.md +2543 -0
- package/CLAUDE.md +110 -0
- package/LICENSE +21 -0
- package/README.md +110 -0
- package/cypress/e2e/control/checkbox.cy.ts +46 -0
- package/cypress/e2e/control/select.cy.ts +56 -0
- package/cypress/e2e/control/text.cy.ts +43 -0
- package/cypress/e2e/editor.cy.ts +67 -0
- package/cypress/e2e/menus/block.cy.ts +38 -0
- package/cypress/e2e/menus/checkbox.cy.ts +33 -0
- package/cypress/e2e/menus/codeblock.cy.ts +34 -0
- package/cypress/e2e/menus/date.cy.ts +28 -0
- package/cypress/e2e/menus/format.cy.ts +40 -0
- package/cypress/e2e/menus/hyperlink.cy.ts +39 -0
- package/cypress/e2e/menus/image.cy.ts +25 -0
- package/cypress/e2e/menus/latex.cy.ts +34 -0
- package/cypress/e2e/menus/pagebreak.cy.ts +21 -0
- package/cypress/e2e/menus/painter.cy.ts +53 -0
- package/cypress/e2e/menus/print.cy.ts +25 -0
- package/cypress/e2e/menus/row.cy.ts +103 -0
- package/cypress/e2e/menus/search.cy.ts +112 -0
- package/cypress/e2e/menus/separator.cy.ts +32 -0
- package/cypress/e2e/menus/table.cy.ts +25 -0
- package/cypress/e2e/menus/text.cy.ts +304 -0
- package/cypress/e2e/menus/title.cy.ts +43 -0
- package/cypress/e2e/menus/undoRedo.cy.ts +49 -0
- package/cypress/e2e/menus/watermark.cy.ts +64 -0
- package/cypress/fixtures/example.json +3 -0
- package/cypress/fixtures/test.png +0 -0
- package/cypress/global.d.ts +13 -0
- package/cypress/support/commands.ts +5 -0
- package/cypress/support/e2e.ts +1 -0
- package/cypress/tsconfig.json +21 -0
- package/cypress.config.ts +10 -0
- package/docs/.vitepress/config.ts +191 -0
- package/docs/.vitepress/theme/components/DeepWikiBadge.vue +21 -0
- package/docs/.vitepress/theme/components/ZreadBadge.vue +21 -0
- package/docs/.vitepress/theme/index.ts +27 -0
- package/docs/en/guide/api-common.md +49 -0
- package/docs/en/guide/api-instance.md +34 -0
- package/docs/en/guide/command-execute.md +1167 -0
- package/docs/en/guide/command-get.md +355 -0
- package/docs/en/guide/contextmenu-custom.md +44 -0
- package/docs/en/guide/contextmenu-internal.md +61 -0
- package/docs/en/guide/eventbus.md +260 -0
- package/docs/en/guide/i18n.md +112 -0
- package/docs/en/guide/listener.md +126 -0
- package/docs/en/guide/option.md +214 -0
- package/docs/en/guide/override.md +57 -0
- package/docs/en/guide/plugin-custom.md +25 -0
- package/docs/en/guide/plugin-internal.md +125 -0
- package/docs/en/guide/schema.md +237 -0
- package/docs/en/guide/shortcut-custom.md +22 -0
- package/docs/en/guide/shortcut-internal.md +189 -0
- package/docs/en/guide/start.md +97 -0
- package/docs/en/index.md +43 -0
- package/docs/guide/api-common.md +49 -0
- package/docs/guide/api-instance.md +34 -0
- package/docs/guide/command-execute.md +1157 -0
- package/docs/guide/command-get.md +353 -0
- package/docs/guide/contextmenu-custom.md +44 -0
- package/docs/guide/contextmenu-internal.md +61 -0
- package/docs/guide/eventbus.md +260 -0
- package/docs/guide/i18n.md +111 -0
- package/docs/guide/listener.md +126 -0
- package/docs/guide/option.md +214 -0
- package/docs/guide/override.md +57 -0
- package/docs/guide/plugin-custom.md +25 -0
- package/docs/guide/plugin-internal.md +125 -0
- package/docs/guide/schema.md +237 -0
- package/docs/guide/shortcut-custom.md +22 -0
- package/docs/guide/shortcut-internal.md +189 -0
- package/docs/guide/start.md +97 -0
- package/docs/index.md +43 -0
- package/docs/public/favicon.png +0 -0
- package/favicon.png +0 -0
- package/index.html +435 -0
- package/package.json +55 -0
- package/pnpm-lock.yaml +4113 -0
- package/scripts/release.js +41 -0
- package/scripts/verifyCommit.js +19 -0
- package/src/assets/images/alignment.svg +1 -0
- package/src/assets/images/arrow-left.svg +1 -0
- package/src/assets/images/arrow-right.svg +1 -0
- package/src/assets/images/block.svg +1 -0
- package/src/assets/images/bold.svg +1 -0
- package/src/assets/images/catalog.svg +1 -0
- package/src/assets/images/center.svg +1 -0
- package/src/assets/images/checkbox.svg +1 -0
- package/src/assets/images/close.svg +1 -0
- package/src/assets/images/codeblock.svg +1 -0
- package/src/assets/images/color.svg +1 -0
- package/src/assets/images/control.svg +1 -0
- package/src/assets/images/date.svg +1 -0
- package/src/assets/images/exit-fullscreen.svg +1 -0
- package/src/assets/images/format.svg +1 -0
- package/src/assets/images/highlight.svg +1 -0
- package/src/assets/images/hyperlink.svg +1 -0
- package/src/assets/images/image.svg +1 -0
- package/src/assets/images/italic.svg +1 -0
- package/src/assets/images/justify.svg +7 -0
- package/src/assets/images/latex.svg +1 -0
- package/src/assets/images/left.svg +1 -0
- package/src/assets/images/line-dash-dot-dot.svg +1 -0
- package/src/assets/images/line-dash-dot.svg +1 -0
- package/src/assets/images/line-dash-large-gap.svg +1 -0
- package/src/assets/images/line-dash-small-gap.svg +1 -0
- package/src/assets/images/line-dot.svg +1 -0
- package/src/assets/images/line-double.svg +1 -0
- package/src/assets/images/line-single.svg +1 -0
- package/src/assets/images/line-wavy.svg +1 -0
- package/src/assets/images/list.svg +1 -0
- package/src/assets/images/option.svg +1 -0
- package/src/assets/images/page-break.svg +1 -0
- package/src/assets/images/page-mode.svg +1 -0
- package/src/assets/images/page-scale-add.svg +1 -0
- package/src/assets/images/page-scale-minus.svg +1 -0
- package/src/assets/images/painter.svg +1 -0
- package/src/assets/images/paper-direction.svg +1 -0
- package/src/assets/images/paper-margin.svg +1 -0
- package/src/assets/images/paper-size.svg +1 -0
- package/src/assets/images/print.svg +1 -0
- package/src/assets/images/radio.svg +4 -0
- package/src/assets/images/redo.svg +1 -0
- package/src/assets/images/request-fullscreen.svg +1 -0
- package/src/assets/images/right.svg +1 -0
- package/src/assets/images/row-margin.svg +1 -0
- package/src/assets/images/search.svg +1 -0
- package/src/assets/images/separator.svg +1 -0
- package/src/assets/images/signature-undo.svg +1 -0
- package/src/assets/images/signature.svg +1 -0
- package/src/assets/images/size-add.svg +1 -0
- package/src/assets/images/size-minus.svg +1 -0
- package/src/assets/images/strikeout.svg +1 -0
- package/src/assets/images/subscript.svg +1 -0
- package/src/assets/images/superscript.svg +1 -0
- package/src/assets/images/table.svg +1 -0
- package/src/assets/images/title.svg +1 -0
- package/src/assets/images/trash.svg +1 -0
- package/src/assets/images/underline.svg +1 -0
- package/src/assets/images/undo.svg +1 -0
- package/src/assets/images/watermark.svg +1 -0
- package/src/assets/images/word-tool.svg +1 -0
- package/src/assets/snapshots/main_v0.2.1.png +0 -0
- package/src/assets/snapshots/main_v0.2.2.png +0 -0
- package/src/assets/snapshots/main_v0.3.0.png +0 -0
- package/src/assets/snapshots/main_v0.3.1.png +0 -0
- package/src/assets/snapshots/main_v0.5.0.png +0 -0
- package/src/assets/snapshots/main_v0.5.1.png +0 -0
- package/src/assets/snapshots/main_v0.6.0.png +0 -0
- package/src/assets/snapshots/main_v0.6.1.png +0 -0
- package/src/assets/snapshots/main_v0.7.0.png +0 -0
- package/src/assets/snapshots/main_v0.7.1.png +0 -0
- package/src/assets/snapshots/main_v0.7.2.png +0 -0
- package/src/assets/snapshots/main_v0.7.3.png +0 -0
- package/src/assets/snapshots/main_v0.7.4.png +0 -0
- package/src/assets/snapshots/main_v0.7.6.png +0 -0
- package/src/assets/snapshots/main_v0.7.7.png +0 -0
- package/src/assets/snapshots/main_v0.8.0.png +0 -0
- package/src/assets/snapshots/main_v0.8.5.png +0 -0
- package/src/assets/snapshots/main_v0.8.6.png +0 -0
- package/src/assets/snapshots/main_v0.8.7.png +0 -0
- package/src/assets/snapshots/main_v0.8.8.png +0 -0
- package/src/assets/snapshots/main_v0.9.0.png +0 -0
- package/src/assets/snapshots/main_v0.9.1.png +0 -0
- package/src/assets/snapshots/main_v0.9.2.png +0 -0
- package/src/assets/snapshots/main_v0.9.23.png +0 -0
- package/src/assets/snapshots/main_v0.9.28.png +0 -0
- package/src/assets/snapshots/main_v0.9.29.png +0 -0
- package/src/assets/snapshots/main_v0.9.3.png +0 -0
- package/src/assets/snapshots/main_v0.9.30.png +0 -0
- package/src/assets/snapshots/main_v0.9.32.png +0 -0
- package/src/assets/snapshots/main_v0.9.35.png +0 -0
- package/src/assets/snapshots/main_v0.9.4.png +0 -0
- package/src/assets/snapshots/main_v0.9.5.png +0 -0
- package/src/assets/snapshots/main_v0.9.6.png +0 -0
- package/src/assets/snapshots/main_v0.9.8.png +0 -0
- package/src/components/dialog/Dialog.ts +171 -0
- package/src/components/dialog/dialog.css +131 -0
- package/src/components/signature/Signature.ts +340 -0
- package/src/components/signature/signature.css +132 -0
- package/src/editor/assets/css/block/block.css +21 -0
- package/src/editor/assets/css/contextmenu/contextmenu.css +196 -0
- package/src/editor/assets/css/control/calculator.css +85 -0
- package/src/editor/assets/css/control/select.css +44 -0
- package/src/editor/assets/css/date/datePicker.css +233 -0
- package/src/editor/assets/css/hyperlink/hyperlink.css +26 -0
- package/src/editor/assets/css/index.css +78 -0
- package/src/editor/assets/css/previewer/previewer.css +122 -0
- package/src/editor/assets/css/resizer/resizer.css +74 -0
- package/src/editor/assets/css/table/table.css +155 -0
- package/src/editor/assets/css/zone/zone.css +61 -0
- package/src/editor/assets/images/close.svg +1 -0
- package/src/editor/assets/images/delete-col.svg +1 -0
- package/src/editor/assets/images/delete-row-col.svg +1 -0
- package/src/editor/assets/images/delete-row.svg +1 -0
- package/src/editor/assets/images/delete-table.svg +1 -0
- package/src/editor/assets/images/image-change.svg +1 -0
- package/src/editor/assets/images/image-download.svg +1 -0
- package/src/editor/assets/images/image-next.svg +1 -0
- package/src/editor/assets/images/image-pre.svg +1 -0
- package/src/editor/assets/images/image.svg +1 -0
- package/src/editor/assets/images/insert-bottom-row.svg +1 -0
- package/src/editor/assets/images/insert-left-col.svg +1 -0
- package/src/editor/assets/images/insert-right-col.svg +1 -0
- package/src/editor/assets/images/insert-row-col.svg +1 -0
- package/src/editor/assets/images/insert-top-row.svg +1 -0
- package/src/editor/assets/images/merge-cancel-cell.svg +1 -0
- package/src/editor/assets/images/merge-cell.svg +1 -0
- package/src/editor/assets/images/original-size.svg +1 -0
- package/src/editor/assets/images/print.svg +1 -0
- package/src/editor/assets/images/rotate.svg +1 -0
- package/src/editor/assets/images/submenu-dropdown.svg +1 -0
- package/src/editor/assets/images/table-border-all.svg +1 -0
- package/src/editor/assets/images/table-border-dash.svg +1 -0
- package/src/editor/assets/images/table-border-empty.svg +1 -0
- package/src/editor/assets/images/table-border-external.svg +1 -0
- package/src/editor/assets/images/table-border-internal.svg +1 -0
- package/src/editor/assets/images/table-border-td-back.svg +1 -0
- package/src/editor/assets/images/table-border-td-bottom.svg +1 -0
- package/src/editor/assets/images/table-border-td-forward.svg +1 -0
- package/src/editor/assets/images/table-border-td-left.svg +1 -0
- package/src/editor/assets/images/table-border-td-right.svg +1 -0
- package/src/editor/assets/images/table-border-td-top.svg +1 -0
- package/src/editor/assets/images/table-border-td.svg +1 -0
- package/src/editor/assets/images/vertical-align-bottom.svg +1 -0
- package/src/editor/assets/images/vertical-align-middle.svg +1 -0
- package/src/editor/assets/images/vertical-align-top.svg +1 -0
- package/src/editor/assets/images/vertical-align.svg +1 -0
- package/src/editor/assets/images/zoom-in.svg +1 -0
- package/src/editor/assets/images/zoom-out.svg +1 -0
- package/src/editor/core/actuator/Actuator.ts +21 -0
- package/src/editor/core/actuator/handlers/positionContextChange.ts +13 -0
- package/src/editor/core/command/Command.ts +312 -0
- package/src/editor/core/command/CommandAdapt.ts +2733 -0
- package/src/editor/core/contextmenu/ContextMenu.ts +363 -0
- package/src/editor/core/contextmenu/menus/controlMenus.ts +25 -0
- package/src/editor/core/contextmenu/menus/globalMenus.ts +66 -0
- package/src/editor/core/contextmenu/menus/hyperlinkMenus.ts +58 -0
- package/src/editor/core/contextmenu/menus/imageMenus.ts +134 -0
- package/src/editor/core/contextmenu/menus/tableMenus.ts +331 -0
- package/src/editor/core/cursor/Cursor.ts +248 -0
- package/src/editor/core/cursor/CursorAgent.ts +75 -0
- package/src/editor/core/draw/Draw.ts +2934 -0
- package/src/editor/core/draw/control/Control.ts +1767 -0
- package/src/editor/core/draw/control/checkbox/CheckboxControl.ts +154 -0
- package/src/editor/core/draw/control/date/DateControl.ts +363 -0
- package/src/editor/core/draw/control/interactive/ControlSearch.ts +214 -0
- package/src/editor/core/draw/control/number/Calculator.ts +183 -0
- package/src/editor/core/draw/control/number/NumberControl.ts +183 -0
- package/src/editor/core/draw/control/radio/RadioControl.ts +68 -0
- package/src/editor/core/draw/control/richtext/Border.ts +52 -0
- package/src/editor/core/draw/control/select/SelectControl.ts +567 -0
- package/src/editor/core/draw/control/text/TextControl.ts +280 -0
- package/src/editor/core/draw/frame/Background.ts +117 -0
- package/src/editor/core/draw/frame/Badge.ts +88 -0
- package/src/editor/core/draw/frame/Footer.ts +155 -0
- package/src/editor/core/draw/frame/Header.ts +158 -0
- package/src/editor/core/draw/frame/LineNumber.ts +43 -0
- package/src/editor/core/draw/frame/Margin.ts +53 -0
- package/src/editor/core/draw/frame/PageBorder.ts +47 -0
- package/src/editor/core/draw/frame/PageNumber.ts +88 -0
- package/src/editor/core/draw/frame/Placeholder.ts +114 -0
- package/src/editor/core/draw/frame/Watermark.ts +188 -0
- package/src/editor/core/draw/graffiti/Graffiti.ts +125 -0
- package/src/editor/core/draw/interactive/Area.ts +312 -0
- package/src/editor/core/draw/interactive/Group.ts +198 -0
- package/src/editor/core/draw/interactive/Search.ts +527 -0
- package/src/editor/core/draw/particle/CheckboxParticle.ts +111 -0
- package/src/editor/core/draw/particle/HyperlinkParticle.ts +86 -0
- package/src/editor/core/draw/particle/ImageParticle.ts +280 -0
- package/src/editor/core/draw/particle/LabelParticle.ts +79 -0
- package/src/editor/core/draw/particle/LineBreakParticle.ts +55 -0
- package/src/editor/core/draw/particle/ListParticle.ts +255 -0
- package/src/editor/core/draw/particle/PageBreakParticle.ts +54 -0
- package/src/editor/core/draw/particle/RadioParticle.ts +99 -0
- package/src/editor/core/draw/particle/SeparatorParticle.ts +37 -0
- package/src/editor/core/draw/particle/SubscriptParticle.ts +23 -0
- package/src/editor/core/draw/particle/SuperscriptParticle.ts +23 -0
- package/src/editor/core/draw/particle/TextParticle.ts +174 -0
- package/src/editor/core/draw/particle/WhiteSpaceParticle.ts +32 -0
- package/src/editor/core/draw/particle/block/BlockParticle.ts +76 -0
- package/src/editor/core/draw/particle/block/modules/BaseBlock.ts +280 -0
- package/src/editor/core/draw/particle/block/modules/IFrameBlock.ts +47 -0
- package/src/editor/core/draw/particle/block/modules/VideoBlock.ts +61 -0
- package/src/editor/core/draw/particle/date/DateParticle.ts +111 -0
- package/src/editor/core/draw/particle/date/DatePicker.ts +577 -0
- package/src/editor/core/draw/particle/latex/LaTexParticle.ts +43 -0
- package/src/editor/core/draw/particle/latex/utils/LaTexUtils.ts +1196 -0
- package/src/editor/core/draw/particle/latex/utils/hershey.ts +1632 -0
- package/src/editor/core/draw/particle/latex/utils/symbols.ts +318 -0
- package/src/editor/core/draw/particle/previewer/Previewer.ts +582 -0
- package/src/editor/core/draw/particle/table/TableOperate.ts +988 -0
- package/src/editor/core/draw/particle/table/TableParticle.ts +558 -0
- package/src/editor/core/draw/particle/table/TableTool.ts +551 -0
- package/src/editor/core/draw/richtext/AbstractRichText.ts +59 -0
- package/src/editor/core/draw/richtext/Highlight.ts +24 -0
- package/src/editor/core/draw/richtext/Strikeout.ts +28 -0
- package/src/editor/core/draw/richtext/Underline.ts +106 -0
- package/src/editor/core/event/CanvasEvent.ts +215 -0
- package/src/editor/core/event/GlobalEvent.ts +173 -0
- package/src/editor/core/event/eventbus/EventBus.ts +50 -0
- package/src/editor/core/event/handlers/click.ts +234 -0
- package/src/editor/core/event/handlers/composition.ts +45 -0
- package/src/editor/core/event/handlers/copy.ts +72 -0
- package/src/editor/core/event/handlers/cut.ts +47 -0
- package/src/editor/core/event/handlers/drag.ts +66 -0
- package/src/editor/core/event/handlers/drop.ts +28 -0
- package/src/editor/core/event/handlers/input.ts +129 -0
- package/src/editor/core/event/handlers/keydown/backspace.ts +161 -0
- package/src/editor/core/event/handlers/keydown/delete.ts +119 -0
- package/src/editor/core/event/handlers/keydown/end.ts +69 -0
- package/src/editor/core/event/handlers/keydown/enter.ts +126 -0
- package/src/editor/core/event/handlers/keydown/home.ts +69 -0
- package/src/editor/core/event/handlers/keydown/index.ts +85 -0
- package/src/editor/core/event/handlers/keydown/left.ts +162 -0
- package/src/editor/core/event/handlers/keydown/right.ts +178 -0
- package/src/editor/core/event/handlers/keydown/tab.ts +41 -0
- package/src/editor/core/event/handlers/keydown/updown.ts +342 -0
- package/src/editor/core/event/handlers/mousedown.ts +262 -0
- package/src/editor/core/event/handlers/mouseleave.ts +14 -0
- package/src/editor/core/event/handlers/mousemove.ts +133 -0
- package/src/editor/core/event/handlers/mouseup.ts +341 -0
- package/src/editor/core/event/handlers/paste.ts +231 -0
- package/src/editor/core/history/HistoryManager.ts +61 -0
- package/src/editor/core/i18n/I18n.ts +51 -0
- package/src/editor/core/i18n/lang/en.json +92 -0
- package/src/editor/core/i18n/lang/zh-CN.json +92 -0
- package/src/editor/core/listener/Listener.ts +41 -0
- package/src/editor/core/observer/ImageObserver.ts +19 -0
- package/src/editor/core/observer/MouseObserver.ts +56 -0
- package/src/editor/core/observer/ScrollObserver.ts +88 -0
- package/src/editor/core/observer/SelectionObserver.ts +143 -0
- package/src/editor/core/override/Override.ts +14 -0
- package/src/editor/core/plugin/Plugin.ts +17 -0
- package/src/editor/core/position/Position.ts +870 -0
- package/src/editor/core/range/RangeManager.ts +723 -0
- package/src/editor/core/register/Register.ts +28 -0
- package/src/editor/core/shortcut/Shortcut.ts +80 -0
- package/src/editor/core/shortcut/keys/listKeys.ts +22 -0
- package/src/editor/core/shortcut/keys/richtextKeys.ts +102 -0
- package/src/editor/core/shortcut/keys/titleKeys.ts +62 -0
- package/src/editor/core/worker/WorkerManager.ts +96 -0
- package/src/editor/core/worker/works/catalog.ts +189 -0
- package/src/editor/core/worker/works/group.ts +34 -0
- package/src/editor/core/worker/works/value.ts +32 -0
- package/src/editor/core/worker/works/wordCount.ts +132 -0
- package/src/editor/core/zone/Zone.ts +183 -0
- package/src/editor/core/zone/ZoneTip.ts +108 -0
- package/src/editor/dataset/constant/Background.ts +10 -0
- package/src/editor/dataset/constant/Badge.ts +6 -0
- package/src/editor/dataset/constant/Checkbox.ts +12 -0
- package/src/editor/dataset/constant/Common.ts +44 -0
- package/src/editor/dataset/constant/ContextMenu.ts +61 -0
- package/src/editor/dataset/constant/Control.ts +14 -0
- package/src/editor/dataset/constant/Cursor.ts +11 -0
- package/src/editor/dataset/constant/Editor.ts +19 -0
- package/src/editor/dataset/constant/Element.ts +173 -0
- package/src/editor/dataset/constant/Footer.ts +10 -0
- package/src/editor/dataset/constant/Graffiti.ts +6 -0
- package/src/editor/dataset/constant/Group.ts +10 -0
- package/src/editor/dataset/constant/Header.ts +10 -0
- package/src/editor/dataset/constant/ImgCaption.ts +8 -0
- package/src/editor/dataset/constant/Label.ts +8 -0
- package/src/editor/dataset/constant/LineBreak.ts +7 -0
- package/src/editor/dataset/constant/LineNumber.ts +11 -0
- package/src/editor/dataset/constant/List.ts +26 -0
- package/src/editor/dataset/constant/PageBorder.ts +8 -0
- package/src/editor/dataset/constant/PageBreak.ts +7 -0
- package/src/editor/dataset/constant/PageNumber.ts +22 -0
- package/src/editor/dataset/constant/Placeholder.ts +9 -0
- package/src/editor/dataset/constant/Radio.ts +12 -0
- package/src/editor/dataset/constant/Regular.ts +23 -0
- package/src/editor/dataset/constant/Separator.ts +6 -0
- package/src/editor/dataset/constant/Shortcut.ts +3 -0
- package/src/editor/dataset/constant/Table.ts +9 -0
- package/src/editor/dataset/constant/Title.ts +38 -0
- package/src/editor/dataset/constant/Watermark.ts +17 -0
- package/src/editor/dataset/constant/WhiteSpace.ts +7 -0
- package/src/editor/dataset/constant/Zone.ts +5 -0
- package/src/editor/dataset/enum/Area.ts +5 -0
- package/src/editor/dataset/enum/Background.ts +11 -0
- package/src/editor/dataset/enum/Block.ts +4 -0
- package/src/editor/dataset/enum/Common.ts +30 -0
- package/src/editor/dataset/enum/Control.ts +39 -0
- package/src/editor/dataset/enum/Editor.ts +51 -0
- package/src/editor/dataset/enum/Element.ts +21 -0
- package/src/editor/dataset/enum/ElementStyle.ts +12 -0
- package/src/editor/dataset/enum/Event.ts +5 -0
- package/src/editor/dataset/enum/KeyMap.ts +85 -0
- package/src/editor/dataset/enum/LineNumber.ts +4 -0
- package/src/editor/dataset/enum/List.ts +23 -0
- package/src/editor/dataset/enum/Observer.ts +6 -0
- package/src/editor/dataset/enum/Row.ts +7 -0
- package/src/editor/dataset/enum/Text.ts +13 -0
- package/src/editor/dataset/enum/Title.ts +8 -0
- package/src/editor/dataset/enum/VerticalAlign.ts +5 -0
- package/src/editor/dataset/enum/Watermark.ts +4 -0
- package/src/editor/dataset/enum/table/Table.ts +19 -0
- package/src/editor/dataset/enum/table/TableTool.ts +4 -0
- package/src/editor/index.ts +241 -0
- package/src/editor/interface/Area.ts +68 -0
- package/src/editor/interface/Background.ts +9 -0
- package/src/editor/interface/Badge.ts +17 -0
- package/src/editor/interface/Block.ts +18 -0
- package/src/editor/interface/Catalog.ts +11 -0
- package/src/editor/interface/Checkbox.ts +17 -0
- package/src/editor/interface/Command.ts +3 -0
- package/src/editor/interface/Common.ts +43 -0
- package/src/editor/interface/Control.ts +250 -0
- package/src/editor/interface/Cursor.ts +7 -0
- package/src/editor/interface/Draw.ts +86 -0
- package/src/editor/interface/Editor.ts +172 -0
- package/src/editor/interface/Element.ts +273 -0
- package/src/editor/interface/Event.ts +27 -0
- package/src/editor/interface/EventBus.ts +46 -0
- package/src/editor/interface/Footer.ts +9 -0
- package/src/editor/interface/Graffiti.ts +15 -0
- package/src/editor/interface/Group.ts +8 -0
- package/src/editor/interface/Header.ts +9 -0
- package/src/editor/interface/Label.ts +8 -0
- package/src/editor/interface/LineBreak.ts +5 -0
- package/src/editor/interface/LineNumber.ts +10 -0
- package/src/editor/interface/Listener.ts +88 -0
- package/src/editor/interface/Margin.ts +1 -0
- package/src/editor/interface/PageBorder.ts +8 -0
- package/src/editor/interface/PageBreak.ts +5 -0
- package/src/editor/interface/PageNumber.ts +16 -0
- package/src/editor/interface/Placeholder.ts +7 -0
- package/src/editor/interface/Plugin.ts +8 -0
- package/src/editor/interface/Position.ts +113 -0
- package/src/editor/interface/Previewer.ts +15 -0
- package/src/editor/interface/Radio.ts +17 -0
- package/src/editor/interface/Range.ts +61 -0
- package/src/editor/interface/Row.ts +25 -0
- package/src/editor/interface/Search.ts +36 -0
- package/src/editor/interface/Separator.ts +4 -0
- package/src/editor/interface/Text.ts +15 -0
- package/src/editor/interface/Title.ts +32 -0
- package/src/editor/interface/Watermark.ts +16 -0
- package/src/editor/interface/WhiteSpace.ts +5 -0
- package/src/editor/interface/Zone.ts +3 -0
- package/src/editor/interface/contextmenu/ContextMenu.ts +76 -0
- package/src/editor/interface/i18n/I18n.ts +7 -0
- package/src/editor/interface/shortcut/Shortcut.ts +14 -0
- package/src/editor/interface/table/Colgroup.ts +4 -0
- package/src/editor/interface/table/Table.ts +9 -0
- package/src/editor/interface/table/Td.ts +36 -0
- package/src/editor/interface/table/Tr.ts +11 -0
- package/src/editor/types/index.d.ts +5 -0
- package/src/editor/utils/clipboard.ts +94 -0
- package/src/editor/utils/element.ts +1877 -0
- package/src/editor/utils/hotkey.ts +5 -0
- package/src/editor/utils/index.ts +445 -0
- package/src/editor/utils/option.ts +253 -0
- package/src/editor/utils/paragraph.ts +28 -0
- package/src/editor/utils/print.ts +99 -0
- package/src/editor/utils/ua.ts +13 -0
- package/src/main.ts +2053 -0
- package/src/mock.ts +611 -0
- package/src/plugins/copy/index.ts +30 -0
- package/src/plugins/markdown/index.ts +118 -0
- package/src/style.css +1079 -0
- package/src/utils/index.ts +45 -0
- package/src/utils/prism.ts +89 -0
- package/src/vite-env.d.ts +1 -0
- package/tsconfig.json +25 -0
- package/vite.config.ts +46 -0
|
@@ -0,0 +1,2934 @@
|
|
|
1
|
+
import { version } from '../../../../package.json'
|
|
2
|
+
import { ZERO } from '../../dataset/constant/Common'
|
|
3
|
+
import { RowFlex } from '../../dataset/enum/Row'
|
|
4
|
+
import {
|
|
5
|
+
IAppendElementListOption,
|
|
6
|
+
IComputeRowListPayload,
|
|
7
|
+
IDrawFloatPayload,
|
|
8
|
+
IDrawOption,
|
|
9
|
+
IDrawPagePayload,
|
|
10
|
+
IDrawRowPayload,
|
|
11
|
+
IGetImageOption,
|
|
12
|
+
IGetOriginValueOption,
|
|
13
|
+
IGetValueOption,
|
|
14
|
+
IPainterOption
|
|
15
|
+
} from '../../interface/Draw'
|
|
16
|
+
import {
|
|
17
|
+
IEditorData,
|
|
18
|
+
IEditorOption,
|
|
19
|
+
IEditorResult,
|
|
20
|
+
ISetValueOption
|
|
21
|
+
} from '../../interface/Editor'
|
|
22
|
+
import {
|
|
23
|
+
IElement,
|
|
24
|
+
IElementMetrics,
|
|
25
|
+
IElementFillRect,
|
|
26
|
+
IElementStyle,
|
|
27
|
+
ISpliceElementListOption,
|
|
28
|
+
IInsertElementListOption
|
|
29
|
+
} from '../../interface/Element'
|
|
30
|
+
import { IRow, IRowElement } from '../../interface/Row'
|
|
31
|
+
import { deepClone, getUUID, nextTick } from '../../utils'
|
|
32
|
+
import { Cursor } from '../cursor/Cursor'
|
|
33
|
+
import { CanvasEvent } from '../event/CanvasEvent'
|
|
34
|
+
import { GlobalEvent } from '../event/GlobalEvent'
|
|
35
|
+
import { HistoryManager } from '../history/HistoryManager'
|
|
36
|
+
import { Listener } from '../listener/Listener'
|
|
37
|
+
import { Position } from '../position/Position'
|
|
38
|
+
import { RangeManager } from '../range/RangeManager'
|
|
39
|
+
import { Background } from './frame/Background'
|
|
40
|
+
import { Highlight } from './richtext/Highlight'
|
|
41
|
+
import { Margin } from './frame/Margin'
|
|
42
|
+
import { Search } from './interactive/Search'
|
|
43
|
+
import { Strikeout } from './richtext/Strikeout'
|
|
44
|
+
import { Underline } from './richtext/Underline'
|
|
45
|
+
import { ElementType } from '../../dataset/enum/Element'
|
|
46
|
+
import { ImageParticle } from './particle/ImageParticle'
|
|
47
|
+
import { LaTexParticle } from './particle/latex/LaTexParticle'
|
|
48
|
+
import { TextParticle } from './particle/TextParticle'
|
|
49
|
+
import { PageNumber } from './frame/PageNumber'
|
|
50
|
+
import { ScrollObserver } from '../observer/ScrollObserver'
|
|
51
|
+
import { SelectionObserver } from '../observer/SelectionObserver'
|
|
52
|
+
import { TableParticle } from './particle/table/TableParticle'
|
|
53
|
+
import { TableTool } from './particle/table/TableTool'
|
|
54
|
+
import { HyperlinkParticle } from './particle/HyperlinkParticle'
|
|
55
|
+
import { LabelParticle } from './particle/LabelParticle'
|
|
56
|
+
import { Header } from './frame/Header'
|
|
57
|
+
import { SuperscriptParticle } from './particle/SuperscriptParticle'
|
|
58
|
+
import { SubscriptParticle } from './particle/SubscriptParticle'
|
|
59
|
+
import { SeparatorParticle } from './particle/SeparatorParticle'
|
|
60
|
+
import { PageBreakParticle } from './particle/PageBreakParticle'
|
|
61
|
+
import { Watermark } from './frame/Watermark'
|
|
62
|
+
import {
|
|
63
|
+
EditorComponent,
|
|
64
|
+
EditorMode,
|
|
65
|
+
EditorZone,
|
|
66
|
+
PageMode,
|
|
67
|
+
PaperDirection,
|
|
68
|
+
WordBreak
|
|
69
|
+
} from '../../dataset/enum/Editor'
|
|
70
|
+
import { Control } from './control/Control'
|
|
71
|
+
import {
|
|
72
|
+
deleteSurroundElementList,
|
|
73
|
+
getIsBlockElement,
|
|
74
|
+
getSlimCloneElementList,
|
|
75
|
+
pickSurroundElementList,
|
|
76
|
+
zipElementList
|
|
77
|
+
} from '../../utils/element'
|
|
78
|
+
import { CheckboxParticle } from './particle/CheckboxParticle'
|
|
79
|
+
import { RadioParticle } from './particle/RadioParticle'
|
|
80
|
+
import { DeepRequired, IPadding } from '../../interface/Common'
|
|
81
|
+
import {
|
|
82
|
+
ControlComponent,
|
|
83
|
+
ControlIndentation
|
|
84
|
+
} from '../../dataset/enum/Control'
|
|
85
|
+
import { formatElementList } from '../../utils/element'
|
|
86
|
+
import { WorkerManager } from '../worker/WorkerManager'
|
|
87
|
+
import { Previewer } from './particle/previewer/Previewer'
|
|
88
|
+
import { DateParticle } from './particle/date/DateParticle'
|
|
89
|
+
import { IMargin } from '../../interface/Margin'
|
|
90
|
+
import { BlockParticle } from './particle/block/BlockParticle'
|
|
91
|
+
import { EDITOR_COMPONENT, EDITOR_PREFIX } from '../../dataset/constant/Editor'
|
|
92
|
+
import { I18n } from '../i18n/I18n'
|
|
93
|
+
import { ImageObserver } from '../observer/ImageObserver'
|
|
94
|
+
import { Zone } from '../zone/Zone'
|
|
95
|
+
import { Footer } from './frame/Footer'
|
|
96
|
+
import {
|
|
97
|
+
IMAGE_ELEMENT_TYPE,
|
|
98
|
+
TEXTLIKE_ELEMENT_TYPE
|
|
99
|
+
} from '../../dataset/constant/Element'
|
|
100
|
+
import { ListParticle } from './particle/ListParticle'
|
|
101
|
+
import { Placeholder } from './frame/Placeholder'
|
|
102
|
+
import { EventBus } from '../event/eventbus/EventBus'
|
|
103
|
+
import { EventBusMap } from '../../interface/EventBus'
|
|
104
|
+
import { Group } from './interactive/Group'
|
|
105
|
+
import { Override } from '../override/Override'
|
|
106
|
+
import { FlexDirection, ImageDisplay } from '../../dataset/enum/Common'
|
|
107
|
+
import {
|
|
108
|
+
PUNCTUATION_REG,
|
|
109
|
+
WHITE_SPACE_REG
|
|
110
|
+
} from '../../dataset/constant/Regular'
|
|
111
|
+
import { LineBreakParticle } from './particle/LineBreakParticle'
|
|
112
|
+
import { WhiteSpaceParticle } from './particle/WhiteSpaceParticle'
|
|
113
|
+
import { MouseObserver } from '../observer/MouseObserver'
|
|
114
|
+
import { LineNumber } from './frame/LineNumber'
|
|
115
|
+
import { PageBorder } from './frame/PageBorder'
|
|
116
|
+
import { ITd } from '../../interface/table/Td'
|
|
117
|
+
import { Actuator } from '../actuator/Actuator'
|
|
118
|
+
import { TableOperate } from './particle/table/TableOperate'
|
|
119
|
+
import { Area } from './interactive/Area'
|
|
120
|
+
import { Badge } from './frame/Badge'
|
|
121
|
+
import { Graffiti } from './graffiti/Graffiti'
|
|
122
|
+
|
|
123
|
+
export class Draw {
|
|
124
|
+
private container: HTMLDivElement
|
|
125
|
+
private pageContainer: HTMLDivElement
|
|
126
|
+
private pageList: HTMLCanvasElement[]
|
|
127
|
+
private ctxList: CanvasRenderingContext2D[]
|
|
128
|
+
private pageNo: number
|
|
129
|
+
private renderCount: number
|
|
130
|
+
private pagePixelRatio: number | null
|
|
131
|
+
private mode: EditorMode
|
|
132
|
+
private options: DeepRequired<IEditorOption>
|
|
133
|
+
private position: Position
|
|
134
|
+
private zone: Zone
|
|
135
|
+
private elementList: IElement[]
|
|
136
|
+
private listener: Listener
|
|
137
|
+
private eventBus: EventBus<EventBusMap>
|
|
138
|
+
private override: Override
|
|
139
|
+
|
|
140
|
+
private i18n: I18n
|
|
141
|
+
private canvasEvent: CanvasEvent
|
|
142
|
+
private globalEvent: GlobalEvent
|
|
143
|
+
private cursor: Cursor
|
|
144
|
+
private range: RangeManager
|
|
145
|
+
private margin: Margin
|
|
146
|
+
private background: Background
|
|
147
|
+
private badge: Badge
|
|
148
|
+
private search: Search
|
|
149
|
+
private group: Group
|
|
150
|
+
private area: Area
|
|
151
|
+
private underline: Underline
|
|
152
|
+
private strikeout: Strikeout
|
|
153
|
+
private highlight: Highlight
|
|
154
|
+
private historyManager: HistoryManager
|
|
155
|
+
private previewer: Previewer
|
|
156
|
+
private imageParticle: ImageParticle
|
|
157
|
+
private laTexParticle: LaTexParticle
|
|
158
|
+
private textParticle: TextParticle
|
|
159
|
+
private tableParticle: TableParticle
|
|
160
|
+
private tableTool: TableTool
|
|
161
|
+
private tableOperate: TableOperate
|
|
162
|
+
private pageNumber: PageNumber
|
|
163
|
+
private lineNumber: LineNumber
|
|
164
|
+
private waterMark: Watermark
|
|
165
|
+
private placeholder: Placeholder
|
|
166
|
+
private header: Header
|
|
167
|
+
private footer: Footer
|
|
168
|
+
private hyperlinkParticle: HyperlinkParticle
|
|
169
|
+
private labelParticle: LabelParticle
|
|
170
|
+
private dateParticle: DateParticle
|
|
171
|
+
private separatorParticle: SeparatorParticle
|
|
172
|
+
private pageBreakParticle: PageBreakParticle
|
|
173
|
+
private superscriptParticle: SuperscriptParticle
|
|
174
|
+
private subscriptParticle: SubscriptParticle
|
|
175
|
+
private checkboxParticle: CheckboxParticle
|
|
176
|
+
private radioParticle: RadioParticle
|
|
177
|
+
private blockParticle: BlockParticle
|
|
178
|
+
private listParticle: ListParticle
|
|
179
|
+
private lineBreakParticle: LineBreakParticle
|
|
180
|
+
private whiteSpaceParticle: WhiteSpaceParticle
|
|
181
|
+
private control: Control
|
|
182
|
+
private pageBorder: PageBorder
|
|
183
|
+
private workerManager: WorkerManager
|
|
184
|
+
private scrollObserver: ScrollObserver
|
|
185
|
+
private selectionObserver: SelectionObserver
|
|
186
|
+
private imageObserver: ImageObserver
|
|
187
|
+
private graffiti: Graffiti
|
|
188
|
+
|
|
189
|
+
private LETTER_REG: RegExp
|
|
190
|
+
private WORD_LIKE_REG: RegExp
|
|
191
|
+
private rowList: IRow[]
|
|
192
|
+
private pageRowList: IRow[][]
|
|
193
|
+
private painterStyle: IElementStyle | null
|
|
194
|
+
private painterOptions: IPainterOption | null
|
|
195
|
+
private visiblePageNoList: number[]
|
|
196
|
+
private intersectionPageNo: number
|
|
197
|
+
private lazyRenderIntersectionObserver: IntersectionObserver | null
|
|
198
|
+
private printModeData: Required<Omit<IEditorData, 'graffiti'>> | null
|
|
199
|
+
|
|
200
|
+
constructor(
|
|
201
|
+
rootContainer: HTMLElement,
|
|
202
|
+
options: DeepRequired<IEditorOption>,
|
|
203
|
+
data: IEditorData,
|
|
204
|
+
listener: Listener,
|
|
205
|
+
eventBus: EventBus<EventBusMap>,
|
|
206
|
+
override: Override
|
|
207
|
+
) {
|
|
208
|
+
this.container = this._wrapContainer(rootContainer)
|
|
209
|
+
this.pageList = []
|
|
210
|
+
this.ctxList = []
|
|
211
|
+
this.pageNo = 0
|
|
212
|
+
this.renderCount = 0
|
|
213
|
+
this.pagePixelRatio = null
|
|
214
|
+
this.mode = options.mode
|
|
215
|
+
this.options = options
|
|
216
|
+
this.elementList = data.main
|
|
217
|
+
this.listener = listener
|
|
218
|
+
this.eventBus = eventBus
|
|
219
|
+
this.override = override
|
|
220
|
+
|
|
221
|
+
this._formatContainer()
|
|
222
|
+
this.pageContainer = this._createPageContainer()
|
|
223
|
+
this._createPage(0)
|
|
224
|
+
|
|
225
|
+
this.i18n = new I18n(options.locale)
|
|
226
|
+
this.historyManager = new HistoryManager(this)
|
|
227
|
+
this.position = new Position(this)
|
|
228
|
+
this.zone = new Zone(this)
|
|
229
|
+
this.range = new RangeManager(this)
|
|
230
|
+
this.margin = new Margin(this)
|
|
231
|
+
this.background = new Background(this)
|
|
232
|
+
this.badge = new Badge(this)
|
|
233
|
+
this.search = new Search(this)
|
|
234
|
+
this.group = new Group(this)
|
|
235
|
+
this.area = new Area(this)
|
|
236
|
+
this.underline = new Underline(this)
|
|
237
|
+
this.strikeout = new Strikeout(this)
|
|
238
|
+
this.highlight = new Highlight(this)
|
|
239
|
+
this.previewer = new Previewer(this)
|
|
240
|
+
this.imageParticle = new ImageParticle(this)
|
|
241
|
+
this.laTexParticle = new LaTexParticle(this)
|
|
242
|
+
this.textParticle = new TextParticle(this)
|
|
243
|
+
this.tableParticle = new TableParticle(this)
|
|
244
|
+
this.tableTool = new TableTool(this)
|
|
245
|
+
this.tableOperate = new TableOperate(this)
|
|
246
|
+
this.pageNumber = new PageNumber(this)
|
|
247
|
+
this.lineNumber = new LineNumber(this)
|
|
248
|
+
this.waterMark = new Watermark(this)
|
|
249
|
+
this.placeholder = new Placeholder(this)
|
|
250
|
+
this.header = new Header(this, data.header)
|
|
251
|
+
this.footer = new Footer(this, data.footer)
|
|
252
|
+
this.hyperlinkParticle = new HyperlinkParticle(this)
|
|
253
|
+
this.labelParticle = new LabelParticle(this)
|
|
254
|
+
this.dateParticle = new DateParticle(this)
|
|
255
|
+
this.separatorParticle = new SeparatorParticle(this)
|
|
256
|
+
this.pageBreakParticle = new PageBreakParticle(this)
|
|
257
|
+
this.superscriptParticle = new SuperscriptParticle()
|
|
258
|
+
this.subscriptParticle = new SubscriptParticle()
|
|
259
|
+
this.checkboxParticle = new CheckboxParticle(this)
|
|
260
|
+
this.radioParticle = new RadioParticle(this)
|
|
261
|
+
this.blockParticle = new BlockParticle(this)
|
|
262
|
+
this.listParticle = new ListParticle(this)
|
|
263
|
+
this.lineBreakParticle = new LineBreakParticle(this)
|
|
264
|
+
this.whiteSpaceParticle = new WhiteSpaceParticle(this)
|
|
265
|
+
this.control = new Control(this)
|
|
266
|
+
this.pageBorder = new PageBorder(this)
|
|
267
|
+
this.graffiti = new Graffiti(this, data.graffiti)
|
|
268
|
+
|
|
269
|
+
this.scrollObserver = new ScrollObserver(this)
|
|
270
|
+
this.selectionObserver = new SelectionObserver(this)
|
|
271
|
+
this.imageObserver = new ImageObserver()
|
|
272
|
+
new MouseObserver(this)
|
|
273
|
+
|
|
274
|
+
this.canvasEvent = new CanvasEvent(this)
|
|
275
|
+
this.cursor = new Cursor(this, this.canvasEvent)
|
|
276
|
+
this.canvasEvent.register()
|
|
277
|
+
this.globalEvent = new GlobalEvent(this, this.canvasEvent)
|
|
278
|
+
this.globalEvent.register()
|
|
279
|
+
|
|
280
|
+
this.workerManager = new WorkerManager(this)
|
|
281
|
+
new Actuator(this)
|
|
282
|
+
|
|
283
|
+
const { letterClass } = options
|
|
284
|
+
this.LETTER_REG = new RegExp(`[${letterClass.join('')}]`)
|
|
285
|
+
this.WORD_LIKE_REG = new RegExp(
|
|
286
|
+
`${letterClass.map(letter => `[^${letter}][${letter}]`).join('|')}`
|
|
287
|
+
)
|
|
288
|
+
this.rowList = []
|
|
289
|
+
this.pageRowList = []
|
|
290
|
+
this.painterStyle = null
|
|
291
|
+
this.painterOptions = null
|
|
292
|
+
this.visiblePageNoList = []
|
|
293
|
+
this.intersectionPageNo = 0
|
|
294
|
+
this.lazyRenderIntersectionObserver = null
|
|
295
|
+
this.printModeData = null
|
|
296
|
+
|
|
297
|
+
// 打印模式优先设置打印数据
|
|
298
|
+
if (this.mode === EditorMode.PRINT) {
|
|
299
|
+
this.setPrintData()
|
|
300
|
+
}
|
|
301
|
+
this.render({
|
|
302
|
+
isInit: true,
|
|
303
|
+
isSetCursor: false,
|
|
304
|
+
isFirstRender: true
|
|
305
|
+
})
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
// 设置打印数据
|
|
309
|
+
public setPrintData() {
|
|
310
|
+
this.printModeData = {
|
|
311
|
+
header: this.header.getElementList(),
|
|
312
|
+
main: this.elementList,
|
|
313
|
+
footer: this.footer.getElementList()
|
|
314
|
+
}
|
|
315
|
+
// 过滤控件辅助元素
|
|
316
|
+
const clonePrintModeData = deepClone(this.printModeData)
|
|
317
|
+
const editorDataKeys: (keyof Omit<IEditorData, 'graffiti'>)[] = [
|
|
318
|
+
'header',
|
|
319
|
+
'main',
|
|
320
|
+
'footer'
|
|
321
|
+
]
|
|
322
|
+
editorDataKeys.forEach(key => {
|
|
323
|
+
clonePrintModeData[key] = this.control.filterAssistElement(
|
|
324
|
+
clonePrintModeData[key]
|
|
325
|
+
)
|
|
326
|
+
})
|
|
327
|
+
this.setEditorData(clonePrintModeData)
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
// 还原打印数据
|
|
331
|
+
public clearPrintData() {
|
|
332
|
+
if (this.printModeData) {
|
|
333
|
+
this.setEditorData(this.printModeData)
|
|
334
|
+
this.printModeData = null
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
|
|
338
|
+
public getLetterReg(): RegExp {
|
|
339
|
+
return this.LETTER_REG
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
public getMode(): EditorMode {
|
|
343
|
+
return this.mode
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
public setMode(payload: EditorMode) {
|
|
347
|
+
if (this.mode === payload) return
|
|
348
|
+
// 设置打印模式
|
|
349
|
+
if (payload === EditorMode.PRINT) {
|
|
350
|
+
this.setPrintData()
|
|
351
|
+
}
|
|
352
|
+
// 取消打印模式
|
|
353
|
+
if (this.mode === EditorMode.PRINT) {
|
|
354
|
+
this.clearPrintData()
|
|
355
|
+
}
|
|
356
|
+
this.clearSideEffect()
|
|
357
|
+
this.range.clearRange()
|
|
358
|
+
this.mode = payload
|
|
359
|
+
this.options.mode = payload
|
|
360
|
+
this.render({
|
|
361
|
+
isSetCursor: false,
|
|
362
|
+
isSubmitHistory: false
|
|
363
|
+
})
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
public isReadonly() {
|
|
367
|
+
if (this.area.getActiveAreaInfo()?.area?.mode) {
|
|
368
|
+
return this.area.isReadonly()
|
|
369
|
+
}
|
|
370
|
+
switch (this.mode) {
|
|
371
|
+
case EditorMode.DESIGN:
|
|
372
|
+
return false
|
|
373
|
+
case EditorMode.READONLY:
|
|
374
|
+
case EditorMode.PRINT:
|
|
375
|
+
case EditorMode.GRAFFITI:
|
|
376
|
+
return true
|
|
377
|
+
case EditorMode.FORM:
|
|
378
|
+
return !this.control.getIsRangeWithinControl()
|
|
379
|
+
default:
|
|
380
|
+
return false
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
public isDisabled() {
|
|
385
|
+
if (this.mode === EditorMode.DESIGN) return false
|
|
386
|
+
const { startIndex, endIndex } = this.range.getRange()
|
|
387
|
+
const elementList = this.getElementList()
|
|
388
|
+
// 优先判断表格单元格
|
|
389
|
+
if (this.getTd()?.disabled) return true
|
|
390
|
+
if (startIndex === endIndex) {
|
|
391
|
+
const startElement = elementList[startIndex]
|
|
392
|
+
const nextElement = elementList[startIndex + 1]
|
|
393
|
+
return !!(
|
|
394
|
+
(startElement?.title?.disabled &&
|
|
395
|
+
nextElement?.title?.disabled &&
|
|
396
|
+
startElement.titleId === nextElement.titleId) ||
|
|
397
|
+
(startElement?.control?.disabled &&
|
|
398
|
+
nextElement?.control?.disabled &&
|
|
399
|
+
startElement.controlId === nextElement.controlId)
|
|
400
|
+
)
|
|
401
|
+
}
|
|
402
|
+
const selectionElementList = elementList.slice(startIndex + 1, endIndex + 1)
|
|
403
|
+
return selectionElementList.some(
|
|
404
|
+
element => element.title?.disabled || element.control?.disabled
|
|
405
|
+
)
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
public isDesignMode() {
|
|
409
|
+
return this.mode === EditorMode.DESIGN
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
public isPrintMode() {
|
|
413
|
+
return this.mode === EditorMode.PRINT
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
public isGraffitiMode() {
|
|
417
|
+
return this.mode === EditorMode.GRAFFITI
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
public getOriginalWidth(): number {
|
|
421
|
+
const { paperDirection, width, height } = this.options
|
|
422
|
+
return paperDirection === PaperDirection.VERTICAL ? width : height
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
public getOriginalHeight(): number {
|
|
426
|
+
const { paperDirection, width, height } = this.options
|
|
427
|
+
return paperDirection === PaperDirection.VERTICAL ? height : width
|
|
428
|
+
}
|
|
429
|
+
|
|
430
|
+
public getWidth(): number {
|
|
431
|
+
return Math.floor(this.getOriginalWidth() * this.options.scale)
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
public getHeight(): number {
|
|
435
|
+
return Math.floor(this.getOriginalHeight() * this.options.scale)
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
public getMainHeight(): number {
|
|
439
|
+
const pageHeight = this.getHeight()
|
|
440
|
+
return pageHeight - this.getMainOuterHeight()
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
public getMainOuterHeight(): number {
|
|
444
|
+
const margins = this.getMargins()
|
|
445
|
+
const headerExtraHeight = this.header.getExtraHeight()
|
|
446
|
+
const footerExtraHeight = this.footer.getExtraHeight()
|
|
447
|
+
return margins[0] + margins[2] + headerExtraHeight + footerExtraHeight
|
|
448
|
+
}
|
|
449
|
+
|
|
450
|
+
public getCanvasWidth(pageNo = -1): number {
|
|
451
|
+
const page = this.getPage(pageNo)
|
|
452
|
+
return page.width
|
|
453
|
+
}
|
|
454
|
+
|
|
455
|
+
public getCanvasHeight(pageNo = -1): number {
|
|
456
|
+
const page = this.getPage(pageNo)
|
|
457
|
+
return page.height
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
public getInnerWidth(): number {
|
|
461
|
+
const width = this.getWidth()
|
|
462
|
+
const margins = this.getMargins()
|
|
463
|
+
return width - margins[1] - margins[3]
|
|
464
|
+
}
|
|
465
|
+
|
|
466
|
+
public getOriginalInnerWidth(): number {
|
|
467
|
+
const width = this.getOriginalWidth()
|
|
468
|
+
const margins = this.getOriginalMargins()
|
|
469
|
+
return width - margins[1] - margins[3]
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
public getContextInnerWidth(): number {
|
|
473
|
+
const positionContext = this.position.getPositionContext()
|
|
474
|
+
if (positionContext.isTable) {
|
|
475
|
+
const { index, trIndex, tdIndex } = positionContext
|
|
476
|
+
const elementList = this.getOriginalElementList()
|
|
477
|
+
const td = elementList[index!].trList![trIndex!].tdList[tdIndex!]
|
|
478
|
+
const tdPadding = this.getTdPadding()
|
|
479
|
+
return td!.width! - tdPadding[1] - tdPadding[3]
|
|
480
|
+
}
|
|
481
|
+
return this.getOriginalInnerWidth()
|
|
482
|
+
}
|
|
483
|
+
|
|
484
|
+
public getMargins(): IMargin {
|
|
485
|
+
return <IMargin>this.getOriginalMargins().map(m => m * this.options.scale)
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
public getOriginalMargins(): number[] {
|
|
489
|
+
const { margins, paperDirection } = this.options
|
|
490
|
+
return paperDirection === PaperDirection.VERTICAL
|
|
491
|
+
? margins
|
|
492
|
+
: [margins[1], margins[2], margins[3], margins[0]]
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
public getPageGap(): number {
|
|
496
|
+
return this.options.pageGap * this.options.scale
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
public getOriginalPageGap(): number {
|
|
500
|
+
return this.options.pageGap
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
public getPageNumberBottom(): number {
|
|
504
|
+
const {
|
|
505
|
+
pageNumber: { bottom },
|
|
506
|
+
scale
|
|
507
|
+
} = this.options
|
|
508
|
+
return bottom * scale
|
|
509
|
+
}
|
|
510
|
+
|
|
511
|
+
public getMarginIndicatorSize(): number {
|
|
512
|
+
return this.options.marginIndicatorSize * this.options.scale
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
public getDefaultBasicRowMarginHeight(): number {
|
|
516
|
+
return this.options.defaultBasicRowMarginHeight * this.options.scale
|
|
517
|
+
}
|
|
518
|
+
|
|
519
|
+
public getHighlightMarginHeight(): number {
|
|
520
|
+
return this.options.highlightMarginHeight * this.options.scale
|
|
521
|
+
}
|
|
522
|
+
|
|
523
|
+
public getTdPadding(): IPadding {
|
|
524
|
+
const {
|
|
525
|
+
table: { tdPadding },
|
|
526
|
+
scale
|
|
527
|
+
} = this.options
|
|
528
|
+
return <IPadding>tdPadding.map(m => m * scale)
|
|
529
|
+
}
|
|
530
|
+
|
|
531
|
+
public getContainer(): HTMLDivElement {
|
|
532
|
+
return this.container
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
public getPageContainer(): HTMLDivElement {
|
|
536
|
+
return this.pageContainer
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
public getVisiblePageNoList(): number[] {
|
|
540
|
+
return this.visiblePageNoList
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
public setVisiblePageNoList(payload: number[]) {
|
|
544
|
+
this.visiblePageNoList = payload
|
|
545
|
+
if (this.listener.visiblePageNoListChange) {
|
|
546
|
+
this.listener.visiblePageNoListChange(this.visiblePageNoList)
|
|
547
|
+
}
|
|
548
|
+
if (this.eventBus.isSubscribe('visiblePageNoListChange')) {
|
|
549
|
+
this.eventBus.emit('visiblePageNoListChange', this.visiblePageNoList)
|
|
550
|
+
}
|
|
551
|
+
}
|
|
552
|
+
|
|
553
|
+
public getIntersectionPageNo(): number {
|
|
554
|
+
return this.intersectionPageNo
|
|
555
|
+
}
|
|
556
|
+
|
|
557
|
+
public setIntersectionPageNo(payload: number) {
|
|
558
|
+
this.intersectionPageNo = payload
|
|
559
|
+
if (this.listener.intersectionPageNoChange) {
|
|
560
|
+
this.listener.intersectionPageNoChange(this.intersectionPageNo)
|
|
561
|
+
}
|
|
562
|
+
if (this.eventBus.isSubscribe('intersectionPageNoChange')) {
|
|
563
|
+
this.eventBus.emit('intersectionPageNoChange', this.intersectionPageNo)
|
|
564
|
+
}
|
|
565
|
+
}
|
|
566
|
+
|
|
567
|
+
public getPageNo(): number {
|
|
568
|
+
return this.pageNo
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
public setPageNo(payload: number) {
|
|
572
|
+
this.pageNo = payload
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
public getRenderCount(): number {
|
|
576
|
+
return this.renderCount
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
public getPage(pageNo = -1): HTMLCanvasElement {
|
|
580
|
+
return this.pageList[~pageNo ? pageNo : this.pageNo]
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
public getPageList(): HTMLCanvasElement[] {
|
|
584
|
+
return this.pageList
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
public getPageCount(): number {
|
|
588
|
+
return this.pageList.length
|
|
589
|
+
}
|
|
590
|
+
|
|
591
|
+
public getTableRowList(sourceElementList: IElement[]): IRow[] {
|
|
592
|
+
const positionContext = this.position.getPositionContext()
|
|
593
|
+
const { index, trIndex, tdIndex } = positionContext
|
|
594
|
+
return sourceElementList[index!].trList![trIndex!].tdList[tdIndex!].rowList!
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
public getOriginalRowList() {
|
|
598
|
+
const zoneManager = this.getZone()
|
|
599
|
+
if (zoneManager.isHeaderActive()) {
|
|
600
|
+
return this.header.getRowList()
|
|
601
|
+
}
|
|
602
|
+
if (zoneManager.isFooterActive()) {
|
|
603
|
+
return this.footer.getRowList()
|
|
604
|
+
}
|
|
605
|
+
return this.rowList
|
|
606
|
+
}
|
|
607
|
+
|
|
608
|
+
public getRowList(): IRow[] {
|
|
609
|
+
const positionContext = this.position.getPositionContext()
|
|
610
|
+
return positionContext.isTable
|
|
611
|
+
? this.getTableRowList(this.getOriginalElementList())
|
|
612
|
+
: this.getOriginalRowList()
|
|
613
|
+
}
|
|
614
|
+
|
|
615
|
+
public getPageRowList(): IRow[][] {
|
|
616
|
+
return this.pageRowList
|
|
617
|
+
}
|
|
618
|
+
|
|
619
|
+
public getCtx(): CanvasRenderingContext2D {
|
|
620
|
+
return this.ctxList[this.pageNo]
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
public getOptions(): DeepRequired<IEditorOption> {
|
|
624
|
+
return this.options
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
public getSearch(): Search {
|
|
628
|
+
return this.search
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
public getGroup(): Group {
|
|
632
|
+
return this.group
|
|
633
|
+
}
|
|
634
|
+
|
|
635
|
+
public getArea(): Area {
|
|
636
|
+
return this.area
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
public getBadge(): Badge {
|
|
640
|
+
return this.badge
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
public getHistoryManager(): HistoryManager {
|
|
644
|
+
return this.historyManager
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
public getPosition(): Position {
|
|
648
|
+
return this.position
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
public getZone(): Zone {
|
|
652
|
+
return this.zone
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
public getRange(): RangeManager {
|
|
656
|
+
return this.range
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
public getLineBreakParticle(): LineBreakParticle {
|
|
660
|
+
return this.lineBreakParticle
|
|
661
|
+
}
|
|
662
|
+
|
|
663
|
+
public getTextParticle(): TextParticle {
|
|
664
|
+
return this.textParticle
|
|
665
|
+
}
|
|
666
|
+
|
|
667
|
+
public getHeaderElementList(): IElement[] {
|
|
668
|
+
return this.header.getElementList()
|
|
669
|
+
}
|
|
670
|
+
|
|
671
|
+
public getTableElementList(sourceElementList: IElement[]): IElement[] {
|
|
672
|
+
const positionContext = this.position.getPositionContext()
|
|
673
|
+
const { index, trIndex, tdIndex } = positionContext
|
|
674
|
+
return (
|
|
675
|
+
sourceElementList[index!].trList?.[trIndex!].tdList[tdIndex!].value || []
|
|
676
|
+
)
|
|
677
|
+
}
|
|
678
|
+
|
|
679
|
+
public getElementList(): IElement[] {
|
|
680
|
+
const positionContext = this.position.getPositionContext()
|
|
681
|
+
const elementList = this.getOriginalElementList()
|
|
682
|
+
return positionContext.isTable
|
|
683
|
+
? this.getTableElementList(elementList)
|
|
684
|
+
: elementList
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
public getMainElementList(): IElement[] {
|
|
688
|
+
const positionContext = this.position.getPositionContext()
|
|
689
|
+
return positionContext.isTable
|
|
690
|
+
? this.getTableElementList(this.elementList)
|
|
691
|
+
: this.elementList
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
public getOriginalElementList() {
|
|
695
|
+
const zoneManager = this.getZone()
|
|
696
|
+
if (zoneManager.isHeaderActive()) {
|
|
697
|
+
return this.getHeaderElementList()
|
|
698
|
+
}
|
|
699
|
+
if (zoneManager.isFooterActive()) {
|
|
700
|
+
return this.getFooterElementList()
|
|
701
|
+
}
|
|
702
|
+
return this.elementList
|
|
703
|
+
}
|
|
704
|
+
|
|
705
|
+
public getOriginalMainElementList(): IElement[] {
|
|
706
|
+
return this.elementList
|
|
707
|
+
}
|
|
708
|
+
|
|
709
|
+
public getFooterElementList(): IElement[] {
|
|
710
|
+
return this.footer.getElementList()
|
|
711
|
+
}
|
|
712
|
+
|
|
713
|
+
public getTd(): ITd | null {
|
|
714
|
+
const positionContext = this.position.getPositionContext()
|
|
715
|
+
const { index, trIndex, tdIndex, isTable } = positionContext
|
|
716
|
+
if (isTable) {
|
|
717
|
+
const elementList = this.getOriginalElementList()
|
|
718
|
+
return elementList[index!].trList![trIndex!].tdList[tdIndex!]
|
|
719
|
+
}
|
|
720
|
+
return null
|
|
721
|
+
}
|
|
722
|
+
|
|
723
|
+
public insertElementList(
|
|
724
|
+
payload: IElement[],
|
|
725
|
+
options: IInsertElementListOption = {}
|
|
726
|
+
) {
|
|
727
|
+
if (!payload.length || !this.range.getIsCanInput()) return
|
|
728
|
+
const { startIndex, endIndex } = this.range.getRange()
|
|
729
|
+
if (!~startIndex && !~endIndex) return
|
|
730
|
+
const { isSubmitHistory = true } = options
|
|
731
|
+
formatElementList(payload, {
|
|
732
|
+
isHandleFirstElement: false,
|
|
733
|
+
editorOptions: this.options
|
|
734
|
+
})
|
|
735
|
+
let curIndex = -1
|
|
736
|
+
// 判断是否在控件内
|
|
737
|
+
let activeControl = this.control.getActiveControl()
|
|
738
|
+
// 光标在控件内如果当前没有被激活,需要手动激活
|
|
739
|
+
if (!activeControl && this.control.getIsRangeWithinControl()) {
|
|
740
|
+
this.control.initControl()
|
|
741
|
+
activeControl = this.control.getActiveControl()
|
|
742
|
+
}
|
|
743
|
+
if (activeControl && this.control.getIsRangeWithinControl()) {
|
|
744
|
+
curIndex = activeControl.setValue(payload, undefined, {
|
|
745
|
+
isIgnoreDisabledRule: true
|
|
746
|
+
})
|
|
747
|
+
this.control.emitControlContentChange()
|
|
748
|
+
} else {
|
|
749
|
+
const elementList = this.getElementList()
|
|
750
|
+
const isCollapsed = startIndex === endIndex
|
|
751
|
+
const start = startIndex + 1
|
|
752
|
+
if (!isCollapsed) {
|
|
753
|
+
this.spliceElementList(elementList, start, endIndex - startIndex)
|
|
754
|
+
}
|
|
755
|
+
this.spliceElementList(elementList, start, 0, payload)
|
|
756
|
+
curIndex = startIndex + payload.length
|
|
757
|
+
// 列表前如有换行符则删除-因为列表内已存在
|
|
758
|
+
const preElement = elementList[start - 1]
|
|
759
|
+
if (
|
|
760
|
+
payload[0].listId &&
|
|
761
|
+
preElement &&
|
|
762
|
+
!preElement.listId &&
|
|
763
|
+
preElement?.value === ZERO &&
|
|
764
|
+
(!preElement.type || preElement.type === ElementType.TEXT)
|
|
765
|
+
) {
|
|
766
|
+
elementList.splice(startIndex, 1)
|
|
767
|
+
curIndex -= 1
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
if (~curIndex) {
|
|
771
|
+
this.range.setRange(curIndex, curIndex)
|
|
772
|
+
this.render({
|
|
773
|
+
curIndex,
|
|
774
|
+
isSubmitHistory
|
|
775
|
+
})
|
|
776
|
+
}
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
public appendElementList(
|
|
780
|
+
elementList: IElement[],
|
|
781
|
+
options: IAppendElementListOption = {}
|
|
782
|
+
) {
|
|
783
|
+
if (!elementList.length) return
|
|
784
|
+
formatElementList(elementList, {
|
|
785
|
+
isHandleFirstElement: false,
|
|
786
|
+
editorOptions: this.options
|
|
787
|
+
})
|
|
788
|
+
let curIndex: number
|
|
789
|
+
const { isPrepend, isSubmitHistory = true } = options
|
|
790
|
+
if (isPrepend) {
|
|
791
|
+
this.elementList.splice(1, 0, ...elementList)
|
|
792
|
+
curIndex = elementList.length
|
|
793
|
+
} else {
|
|
794
|
+
this.elementList.push(...elementList)
|
|
795
|
+
curIndex = this.elementList.length - 1
|
|
796
|
+
}
|
|
797
|
+
this.range.setRange(curIndex, curIndex)
|
|
798
|
+
this.render({
|
|
799
|
+
curIndex,
|
|
800
|
+
isSubmitHistory
|
|
801
|
+
})
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
public spliceElementList(
|
|
805
|
+
elementList: IElement[],
|
|
806
|
+
start: number,
|
|
807
|
+
deleteCount: number,
|
|
808
|
+
items?: IElement[],
|
|
809
|
+
options?: ISpliceElementListOption
|
|
810
|
+
) {
|
|
811
|
+
const { isIgnoreDeletedRule = false } = options || {}
|
|
812
|
+
const { group, modeRule } = this.options
|
|
813
|
+
if (deleteCount > 0) {
|
|
814
|
+
// 当最后元素与开始元素列表信息不一致时:清除当前列表信息
|
|
815
|
+
const endIndex = start + deleteCount
|
|
816
|
+
const endElement = elementList[endIndex]
|
|
817
|
+
const endElementListId = endElement?.listId
|
|
818
|
+
if (
|
|
819
|
+
endElementListId &&
|
|
820
|
+
elementList[start - 1]?.listId !== endElementListId
|
|
821
|
+
) {
|
|
822
|
+
let startIndex = endIndex
|
|
823
|
+
while (startIndex < elementList.length) {
|
|
824
|
+
const curElement = elementList[startIndex]
|
|
825
|
+
if (
|
|
826
|
+
curElement.listId !== endElementListId ||
|
|
827
|
+
curElement.value === ZERO
|
|
828
|
+
) {
|
|
829
|
+
break
|
|
830
|
+
}
|
|
831
|
+
delete curElement.listId
|
|
832
|
+
delete curElement.listType
|
|
833
|
+
delete curElement.listStyle
|
|
834
|
+
startIndex++
|
|
835
|
+
}
|
|
836
|
+
}
|
|
837
|
+
// 非明确忽略删除规则 && 非设计模式 && 非光标在控件内(控件内控制) =》 校验删除规则
|
|
838
|
+
if (
|
|
839
|
+
!isIgnoreDeletedRule &&
|
|
840
|
+
!this.isDesignMode() &&
|
|
841
|
+
!this.control.getIsRangeWithinControl()
|
|
842
|
+
) {
|
|
843
|
+
const tdDeletable = this.getTd()?.deletable
|
|
844
|
+
let deleteIndex = endIndex - 1
|
|
845
|
+
while (deleteIndex >= start) {
|
|
846
|
+
const deleteElement = elementList[deleteIndex]
|
|
847
|
+
if (
|
|
848
|
+
deleteElement?.hide ||
|
|
849
|
+
deleteElement?.control?.hide ||
|
|
850
|
+
deleteElement?.area?.hide ||
|
|
851
|
+
(tdDeletable !== false &&
|
|
852
|
+
deleteElement?.control?.deletable !== false &&
|
|
853
|
+
(!deleteElement.controlId ||
|
|
854
|
+
this.mode !== EditorMode.FORM ||
|
|
855
|
+
!modeRule[this.mode].controlDeletableDisabled) &&
|
|
856
|
+
deleteElement?.title?.deletable !== false &&
|
|
857
|
+
(group.deletable !== false || !deleteElement.groupIds?.length) &&
|
|
858
|
+
(deleteElement?.area?.deletable !== false ||
|
|
859
|
+
deleteElement?.areaIndex !== 0))
|
|
860
|
+
) {
|
|
861
|
+
elementList.splice(deleteIndex, 1)
|
|
862
|
+
}
|
|
863
|
+
deleteIndex--
|
|
864
|
+
}
|
|
865
|
+
} else {
|
|
866
|
+
elementList.splice(start, deleteCount)
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
// 循环添加,避免使用解构影响性能
|
|
870
|
+
if (items?.length) {
|
|
871
|
+
for (let i = 0; i < items.length; i++) {
|
|
872
|
+
elementList.splice(start + i, 0, items[i])
|
|
873
|
+
}
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
public getCanvasEvent(): CanvasEvent {
|
|
878
|
+
return this.canvasEvent
|
|
879
|
+
}
|
|
880
|
+
|
|
881
|
+
public getGlobalEvent(): GlobalEvent {
|
|
882
|
+
return this.globalEvent
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
public getListener(): Listener {
|
|
886
|
+
return this.listener
|
|
887
|
+
}
|
|
888
|
+
|
|
889
|
+
public getEventBus(): EventBus<EventBusMap> {
|
|
890
|
+
return this.eventBus
|
|
891
|
+
}
|
|
892
|
+
|
|
893
|
+
public getOverride(): Override {
|
|
894
|
+
return this.override
|
|
895
|
+
}
|
|
896
|
+
|
|
897
|
+
public getCursor(): Cursor {
|
|
898
|
+
return this.cursor
|
|
899
|
+
}
|
|
900
|
+
|
|
901
|
+
public getPreviewer(): Previewer {
|
|
902
|
+
return this.previewer
|
|
903
|
+
}
|
|
904
|
+
|
|
905
|
+
public getImageParticle(): ImageParticle {
|
|
906
|
+
return this.imageParticle
|
|
907
|
+
}
|
|
908
|
+
|
|
909
|
+
public getTableTool(): TableTool {
|
|
910
|
+
return this.tableTool
|
|
911
|
+
}
|
|
912
|
+
|
|
913
|
+
public getTableOperate(): TableOperate {
|
|
914
|
+
return this.tableOperate
|
|
915
|
+
}
|
|
916
|
+
|
|
917
|
+
public getTableParticle(): TableParticle {
|
|
918
|
+
return this.tableParticle
|
|
919
|
+
}
|
|
920
|
+
|
|
921
|
+
public getHeader(): Header {
|
|
922
|
+
return this.header
|
|
923
|
+
}
|
|
924
|
+
|
|
925
|
+
public getFooter(): Footer {
|
|
926
|
+
return this.footer
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
public getHyperlinkParticle(): HyperlinkParticle {
|
|
930
|
+
return this.hyperlinkParticle
|
|
931
|
+
}
|
|
932
|
+
|
|
933
|
+
public getDateParticle(): DateParticle {
|
|
934
|
+
return this.dateParticle
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
public getListParticle(): ListParticle {
|
|
938
|
+
return this.listParticle
|
|
939
|
+
}
|
|
940
|
+
|
|
941
|
+
public getCheckboxParticle(): CheckboxParticle {
|
|
942
|
+
return this.checkboxParticle
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
public getRadioParticle(): RadioParticle {
|
|
946
|
+
return this.radioParticle
|
|
947
|
+
}
|
|
948
|
+
|
|
949
|
+
public getControl(): Control {
|
|
950
|
+
return this.control
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
public getWorkerManager(): WorkerManager {
|
|
954
|
+
return this.workerManager
|
|
955
|
+
}
|
|
956
|
+
|
|
957
|
+
public getImageObserver(): ImageObserver {
|
|
958
|
+
return this.imageObserver
|
|
959
|
+
}
|
|
960
|
+
|
|
961
|
+
public getI18n(): I18n {
|
|
962
|
+
return this.i18n
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
public getGraffiti(): Graffiti {
|
|
966
|
+
return this.graffiti
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
public getRowCount(): number {
|
|
970
|
+
return this.getRowList().length
|
|
971
|
+
}
|
|
972
|
+
|
|
973
|
+
public async getDataURL(payload: IGetImageOption = {}): Promise<string[]> {
|
|
974
|
+
const { pixelRatio, mode } = payload
|
|
975
|
+
// 放大像素比
|
|
976
|
+
if (pixelRatio) {
|
|
977
|
+
this.setPagePixelRatio(pixelRatio)
|
|
978
|
+
}
|
|
979
|
+
// 不同模式
|
|
980
|
+
const currentMode = this.mode
|
|
981
|
+
const isSwitchMode = !!mode && currentMode !== mode
|
|
982
|
+
if (isSwitchMode) {
|
|
983
|
+
this.setMode(mode)
|
|
984
|
+
}
|
|
985
|
+
this.render({
|
|
986
|
+
isLazy: false,
|
|
987
|
+
isCompute: false,
|
|
988
|
+
isSetCursor: false,
|
|
989
|
+
isSubmitHistory: false
|
|
990
|
+
})
|
|
991
|
+
await this.imageObserver.allSettled()
|
|
992
|
+
const dataUrlList = this.pageList.map(c => c.toDataURL())
|
|
993
|
+
// 还原
|
|
994
|
+
if (pixelRatio) {
|
|
995
|
+
this.setPagePixelRatio(null)
|
|
996
|
+
}
|
|
997
|
+
if (isSwitchMode) {
|
|
998
|
+
this.setMode(currentMode)
|
|
999
|
+
}
|
|
1000
|
+
return dataUrlList
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
public getPainterStyle(): IElementStyle | null {
|
|
1004
|
+
return this.painterStyle && Object.keys(this.painterStyle).length
|
|
1005
|
+
? this.painterStyle
|
|
1006
|
+
: null
|
|
1007
|
+
}
|
|
1008
|
+
|
|
1009
|
+
public getPainterOptions(): IPainterOption | null {
|
|
1010
|
+
return this.painterOptions
|
|
1011
|
+
}
|
|
1012
|
+
|
|
1013
|
+
public setPainterStyle(
|
|
1014
|
+
payload: IElementStyle | null,
|
|
1015
|
+
options?: IPainterOption
|
|
1016
|
+
) {
|
|
1017
|
+
this.painterStyle = payload
|
|
1018
|
+
this.painterOptions = options || null
|
|
1019
|
+
if (this.getPainterStyle()) {
|
|
1020
|
+
this.pageList.forEach(c => (c.style.cursor = 'copy'))
|
|
1021
|
+
}
|
|
1022
|
+
}
|
|
1023
|
+
|
|
1024
|
+
public setDefaultRange() {
|
|
1025
|
+
if (!this.elementList.length) return
|
|
1026
|
+
setTimeout(() => {
|
|
1027
|
+
const curIndex = this.elementList.length - 1
|
|
1028
|
+
this.range.setRange(curIndex, curIndex)
|
|
1029
|
+
this.range.setRangeStyle()
|
|
1030
|
+
})
|
|
1031
|
+
}
|
|
1032
|
+
|
|
1033
|
+
public getIsPagingMode(): boolean {
|
|
1034
|
+
return this.options.pageMode === PageMode.PAGING
|
|
1035
|
+
}
|
|
1036
|
+
|
|
1037
|
+
public setPageMode(payload: PageMode) {
|
|
1038
|
+
if (!payload || this.options.pageMode === payload) return
|
|
1039
|
+
this.options.pageMode = payload
|
|
1040
|
+
// 纸张大小重置
|
|
1041
|
+
if (payload === PageMode.PAGING) {
|
|
1042
|
+
const { height } = this.options
|
|
1043
|
+
const dpr = this.getPagePixelRatio()
|
|
1044
|
+
const canvas = this.pageList[0]
|
|
1045
|
+
canvas.style.height = `${height}px`
|
|
1046
|
+
canvas.height = height * dpr
|
|
1047
|
+
// canvas尺寸发生变化,上下文被重置
|
|
1048
|
+
this._initPageContext(this.ctxList[0])
|
|
1049
|
+
} else {
|
|
1050
|
+
// 连页模式:移除懒加载监听&清空页眉页脚计算数据
|
|
1051
|
+
this._disconnectLazyRender()
|
|
1052
|
+
this.header.recovery()
|
|
1053
|
+
this.footer.recovery()
|
|
1054
|
+
this.zone.setZone(EditorZone.MAIN)
|
|
1055
|
+
}
|
|
1056
|
+
const { startIndex } = this.range.getRange()
|
|
1057
|
+
const isCollapsed = this.range.getIsCollapsed()
|
|
1058
|
+
this.render({
|
|
1059
|
+
isSetCursor: true,
|
|
1060
|
+
curIndex: startIndex,
|
|
1061
|
+
isSubmitHistory: false
|
|
1062
|
+
})
|
|
1063
|
+
// 重新定位避免事件监听丢失
|
|
1064
|
+
if (!isCollapsed) {
|
|
1065
|
+
this.cursor.drawCursor({
|
|
1066
|
+
isShow: false
|
|
1067
|
+
})
|
|
1068
|
+
}
|
|
1069
|
+
// 回调
|
|
1070
|
+
setTimeout(() => {
|
|
1071
|
+
if (this.listener.pageModeChange) {
|
|
1072
|
+
this.listener.pageModeChange(payload)
|
|
1073
|
+
}
|
|
1074
|
+
if (this.eventBus.isSubscribe('pageModeChange')) {
|
|
1075
|
+
this.eventBus.emit('pageModeChange', payload)
|
|
1076
|
+
}
|
|
1077
|
+
})
|
|
1078
|
+
}
|
|
1079
|
+
|
|
1080
|
+
public setPageScale(payload: number) {
|
|
1081
|
+
const dpr = this.getPagePixelRatio()
|
|
1082
|
+
this.options.scale = payload
|
|
1083
|
+
const width = this.getWidth()
|
|
1084
|
+
const height = this.getHeight()
|
|
1085
|
+
this.container.style.width = `${width}px`
|
|
1086
|
+
this.pageList.forEach((p, i) => {
|
|
1087
|
+
p.width = width * dpr
|
|
1088
|
+
p.height = height * dpr
|
|
1089
|
+
p.style.width = `${width}px`
|
|
1090
|
+
p.style.height = `${height}px`
|
|
1091
|
+
p.style.marginBottom = `${this.getPageGap()}px`
|
|
1092
|
+
this._initPageContext(this.ctxList[i])
|
|
1093
|
+
})
|
|
1094
|
+
const cursorPosition = this.position.getCursorPosition()
|
|
1095
|
+
this.render({
|
|
1096
|
+
isSubmitHistory: false,
|
|
1097
|
+
isSetCursor: !!cursorPosition,
|
|
1098
|
+
curIndex: cursorPosition?.index
|
|
1099
|
+
})
|
|
1100
|
+
if (this.listener.pageScaleChange) {
|
|
1101
|
+
this.listener.pageScaleChange(payload)
|
|
1102
|
+
}
|
|
1103
|
+
if (this.eventBus.isSubscribe('pageScaleChange')) {
|
|
1104
|
+
this.eventBus.emit('pageScaleChange', payload)
|
|
1105
|
+
}
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
public getPagePixelRatio(): number {
|
|
1109
|
+
return this.pagePixelRatio || window.devicePixelRatio
|
|
1110
|
+
}
|
|
1111
|
+
|
|
1112
|
+
public setPagePixelRatio(payload: number | null) {
|
|
1113
|
+
if (
|
|
1114
|
+
(!this.pagePixelRatio && payload === window.devicePixelRatio) ||
|
|
1115
|
+
payload === this.pagePixelRatio
|
|
1116
|
+
) {
|
|
1117
|
+
return
|
|
1118
|
+
}
|
|
1119
|
+
this.pagePixelRatio = payload
|
|
1120
|
+
this.setPageDevicePixel()
|
|
1121
|
+
}
|
|
1122
|
+
|
|
1123
|
+
public setPageDevicePixel() {
|
|
1124
|
+
const dpr = this.getPagePixelRatio()
|
|
1125
|
+
const width = this.getWidth()
|
|
1126
|
+
const height = this.getHeight()
|
|
1127
|
+
this.pageList.forEach((p, i) => {
|
|
1128
|
+
p.width = width * dpr
|
|
1129
|
+
p.height = height * dpr
|
|
1130
|
+
this._initPageContext(this.ctxList[i])
|
|
1131
|
+
})
|
|
1132
|
+
this.render({
|
|
1133
|
+
isSubmitHistory: false,
|
|
1134
|
+
isSetCursor: false
|
|
1135
|
+
})
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1138
|
+
public setPaperSize(width: number, height: number) {
|
|
1139
|
+
this.options.width = width
|
|
1140
|
+
this.options.height = height
|
|
1141
|
+
const dpr = this.getPagePixelRatio()
|
|
1142
|
+
const realWidth = this.getWidth()
|
|
1143
|
+
const realHeight = this.getHeight()
|
|
1144
|
+
this.container.style.width = `${realWidth}px`
|
|
1145
|
+
this.pageList.forEach((p, i) => {
|
|
1146
|
+
p.width = realWidth * dpr
|
|
1147
|
+
p.height = realHeight * dpr
|
|
1148
|
+
p.style.width = `${realWidth}px`
|
|
1149
|
+
p.style.height = `${realHeight}px`
|
|
1150
|
+
this._initPageContext(this.ctxList[i])
|
|
1151
|
+
})
|
|
1152
|
+
this.render({
|
|
1153
|
+
isSubmitHistory: false,
|
|
1154
|
+
isSetCursor: false
|
|
1155
|
+
})
|
|
1156
|
+
}
|
|
1157
|
+
|
|
1158
|
+
public setPaperDirection(payload: PaperDirection) {
|
|
1159
|
+
const dpr = this.getPagePixelRatio()
|
|
1160
|
+
this.options.paperDirection = payload
|
|
1161
|
+
const width = this.getWidth()
|
|
1162
|
+
const height = this.getHeight()
|
|
1163
|
+
this.container.style.width = `${width}px`
|
|
1164
|
+
this.pageList.forEach((p, i) => {
|
|
1165
|
+
p.width = width * dpr
|
|
1166
|
+
p.height = height * dpr
|
|
1167
|
+
p.style.width = `${width}px`
|
|
1168
|
+
p.style.height = `${height}px`
|
|
1169
|
+
this._initPageContext(this.ctxList[i])
|
|
1170
|
+
})
|
|
1171
|
+
this.render({
|
|
1172
|
+
isSubmitHistory: false,
|
|
1173
|
+
isSetCursor: false
|
|
1174
|
+
})
|
|
1175
|
+
}
|
|
1176
|
+
|
|
1177
|
+
public setPaperMargin(payload: IMargin) {
|
|
1178
|
+
this.options.margins = payload
|
|
1179
|
+
this.render({
|
|
1180
|
+
isSubmitHistory: false,
|
|
1181
|
+
isSetCursor: false
|
|
1182
|
+
})
|
|
1183
|
+
}
|
|
1184
|
+
|
|
1185
|
+
public getOriginValue(
|
|
1186
|
+
options: IGetOriginValueOption = {}
|
|
1187
|
+
): Required<IEditorData> {
|
|
1188
|
+
const { pageNo } = options
|
|
1189
|
+
let mainElementList = this.elementList
|
|
1190
|
+
if (
|
|
1191
|
+
Number.isInteger(pageNo) &&
|
|
1192
|
+
pageNo! >= 0 &&
|
|
1193
|
+
pageNo! < this.pageRowList.length
|
|
1194
|
+
) {
|
|
1195
|
+
mainElementList = this.pageRowList[pageNo!].flatMap(
|
|
1196
|
+
row => row.elementList
|
|
1197
|
+
)
|
|
1198
|
+
}
|
|
1199
|
+
const data: Required<IEditorData> = {
|
|
1200
|
+
header: this.getHeaderElementList(),
|
|
1201
|
+
main: mainElementList,
|
|
1202
|
+
footer: this.getFooterElementList(),
|
|
1203
|
+
graffiti: this.graffiti.getValue()
|
|
1204
|
+
}
|
|
1205
|
+
return data
|
|
1206
|
+
}
|
|
1207
|
+
|
|
1208
|
+
public getValue(options: IGetValueOption = {}): IEditorResult {
|
|
1209
|
+
const originData = this.getOriginValue(options)
|
|
1210
|
+
const { extraPickAttrs } = options
|
|
1211
|
+
const data: IEditorData = {
|
|
1212
|
+
header: zipElementList(originData.header, {
|
|
1213
|
+
extraPickAttrs
|
|
1214
|
+
}),
|
|
1215
|
+
main: zipElementList(originData.main, {
|
|
1216
|
+
extraPickAttrs,
|
|
1217
|
+
isClassifyArea: true
|
|
1218
|
+
}),
|
|
1219
|
+
footer: zipElementList(originData.footer, {
|
|
1220
|
+
extraPickAttrs
|
|
1221
|
+
}),
|
|
1222
|
+
graffiti: originData.graffiti
|
|
1223
|
+
}
|
|
1224
|
+
return {
|
|
1225
|
+
version,
|
|
1226
|
+
data,
|
|
1227
|
+
options: deepClone(this.options)
|
|
1228
|
+
}
|
|
1229
|
+
}
|
|
1230
|
+
|
|
1231
|
+
public setValue(payload: Partial<IEditorData>, options?: ISetValueOption) {
|
|
1232
|
+
const { header, main, footer } = deepClone(payload)
|
|
1233
|
+
if (!header && !main && !footer) return
|
|
1234
|
+
const { isSetCursor = false } = options || {}
|
|
1235
|
+
const pageComponentData = [header, main, footer]
|
|
1236
|
+
pageComponentData.forEach(data => {
|
|
1237
|
+
if (!data) return
|
|
1238
|
+
formatElementList(data, {
|
|
1239
|
+
editorOptions: this.options,
|
|
1240
|
+
isForceCompensation: true
|
|
1241
|
+
})
|
|
1242
|
+
})
|
|
1243
|
+
this.setEditorData({
|
|
1244
|
+
header,
|
|
1245
|
+
main,
|
|
1246
|
+
footer
|
|
1247
|
+
})
|
|
1248
|
+
// 渲染&计算&清空历史记录
|
|
1249
|
+
this.historyManager.recovery()
|
|
1250
|
+
const curIndex = isSetCursor
|
|
1251
|
+
? main?.length
|
|
1252
|
+
? main.length - 1
|
|
1253
|
+
: 0
|
|
1254
|
+
: undefined
|
|
1255
|
+
if (curIndex !== undefined) {
|
|
1256
|
+
this.range.setRange(curIndex, curIndex)
|
|
1257
|
+
}
|
|
1258
|
+
this.render({
|
|
1259
|
+
curIndex,
|
|
1260
|
+
isSetCursor,
|
|
1261
|
+
isFirstRender: true
|
|
1262
|
+
})
|
|
1263
|
+
}
|
|
1264
|
+
|
|
1265
|
+
public setEditorData(payload: Partial<Omit<IEditorData, 'graffiti'>>) {
|
|
1266
|
+
const { header, main, footer } = payload
|
|
1267
|
+
if (header) {
|
|
1268
|
+
this.header.setElementList(header)
|
|
1269
|
+
}
|
|
1270
|
+
if (main) {
|
|
1271
|
+
this.elementList = main
|
|
1272
|
+
}
|
|
1273
|
+
if (footer) {
|
|
1274
|
+
this.footer.setElementList(footer)
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
private _wrapContainer(rootContainer: HTMLElement): HTMLDivElement {
|
|
1279
|
+
const container = document.createElement('div')
|
|
1280
|
+
rootContainer.append(container)
|
|
1281
|
+
return container
|
|
1282
|
+
}
|
|
1283
|
+
|
|
1284
|
+
private _formatContainer() {
|
|
1285
|
+
// 容器宽度需跟随纸张宽度
|
|
1286
|
+
this.container.style.position = 'relative'
|
|
1287
|
+
this.container.style.width = `${this.getWidth()}px`
|
|
1288
|
+
this.container.setAttribute(EDITOR_COMPONENT, EditorComponent.MAIN)
|
|
1289
|
+
}
|
|
1290
|
+
|
|
1291
|
+
private _createPageContainer(): HTMLDivElement {
|
|
1292
|
+
const pageContainer = document.createElement('div')
|
|
1293
|
+
pageContainer.classList.add(`${EDITOR_PREFIX}-page-container`)
|
|
1294
|
+
this.container.append(pageContainer)
|
|
1295
|
+
return pageContainer
|
|
1296
|
+
}
|
|
1297
|
+
|
|
1298
|
+
private _createPage(pageNo: number) {
|
|
1299
|
+
const width = this.getWidth()
|
|
1300
|
+
const height = this.getHeight()
|
|
1301
|
+
const canvas = document.createElement('canvas')
|
|
1302
|
+
canvas.style.width = `${width}px`
|
|
1303
|
+
canvas.style.height = `${height}px`
|
|
1304
|
+
canvas.style.display = 'block'
|
|
1305
|
+
canvas.style.backgroundColor = '#ffffff'
|
|
1306
|
+
canvas.style.marginBottom = `${this.getPageGap()}px`
|
|
1307
|
+
canvas.setAttribute('data-index', String(pageNo))
|
|
1308
|
+
this.pageContainer.append(canvas)
|
|
1309
|
+
// 调整分辨率
|
|
1310
|
+
const dpr = this.getPagePixelRatio()
|
|
1311
|
+
canvas.width = width * dpr
|
|
1312
|
+
canvas.height = height * dpr
|
|
1313
|
+
canvas.style.cursor = 'text'
|
|
1314
|
+
const ctx = canvas.getContext('2d')!
|
|
1315
|
+
// 初始化上下文配置
|
|
1316
|
+
this._initPageContext(ctx)
|
|
1317
|
+
// 缓存上下文
|
|
1318
|
+
this.pageList.push(canvas)
|
|
1319
|
+
this.ctxList.push(ctx)
|
|
1320
|
+
}
|
|
1321
|
+
|
|
1322
|
+
private _initPageContext(ctx: CanvasRenderingContext2D) {
|
|
1323
|
+
const dpr = this.getPagePixelRatio()
|
|
1324
|
+
ctx.scale(dpr, dpr)
|
|
1325
|
+
// 重置以下属性是因部分浏览器(chrome)会应用css样式
|
|
1326
|
+
ctx.letterSpacing = '0px'
|
|
1327
|
+
ctx.wordSpacing = '0px'
|
|
1328
|
+
ctx.direction = 'ltr'
|
|
1329
|
+
}
|
|
1330
|
+
|
|
1331
|
+
public getElementFont(el: IElement, scale = 1): string {
|
|
1332
|
+
const { defaultSize, defaultFont } = this.options
|
|
1333
|
+
const font = el.font || defaultFont
|
|
1334
|
+
const size = el.actualSize || el.size || defaultSize
|
|
1335
|
+
return `${el.italic ? 'italic ' : ''}${el.bold ? 'bold ' : ''}${
|
|
1336
|
+
size * scale
|
|
1337
|
+
}px ${font}`
|
|
1338
|
+
}
|
|
1339
|
+
|
|
1340
|
+
public getElementSize(el: IElement) {
|
|
1341
|
+
return el.actualSize || el.size || this.options.defaultSize
|
|
1342
|
+
}
|
|
1343
|
+
|
|
1344
|
+
public getElementRowMargin(el: IElement) {
|
|
1345
|
+
const {
|
|
1346
|
+
defaultSize,
|
|
1347
|
+
defaultBasicRowMarginHeight,
|
|
1348
|
+
defaultRowMargin,
|
|
1349
|
+
scale
|
|
1350
|
+
} = this.options
|
|
1351
|
+
// 字体在12-30之间,行间距不变,小于12按比例缩小,大于30按比例放大
|
|
1352
|
+
const fontSize = el.size || defaultSize
|
|
1353
|
+
let ratio = 1
|
|
1354
|
+
if (fontSize < 12) {
|
|
1355
|
+
ratio = fontSize / 12
|
|
1356
|
+
} else if (fontSize > 30) {
|
|
1357
|
+
ratio = 1 + (fontSize - 30) / 30
|
|
1358
|
+
}
|
|
1359
|
+
return (
|
|
1360
|
+
defaultBasicRowMarginHeight *
|
|
1361
|
+
ratio *
|
|
1362
|
+
(el.rowMargin ?? defaultRowMargin) *
|
|
1363
|
+
scale
|
|
1364
|
+
)
|
|
1365
|
+
}
|
|
1366
|
+
|
|
1367
|
+
public computeRowList(payload: IComputeRowListPayload) {
|
|
1368
|
+
const {
|
|
1369
|
+
innerWidth,
|
|
1370
|
+
elementList,
|
|
1371
|
+
isPagingMode = false,
|
|
1372
|
+
isFromTable = false,
|
|
1373
|
+
startX = 0,
|
|
1374
|
+
startY = 0,
|
|
1375
|
+
pageHeight = 0,
|
|
1376
|
+
mainOuterHeight = 0,
|
|
1377
|
+
surroundElementList = []
|
|
1378
|
+
} = payload
|
|
1379
|
+
const {
|
|
1380
|
+
defaultSize,
|
|
1381
|
+
scale,
|
|
1382
|
+
imgCaption,
|
|
1383
|
+
table: { tdPadding, defaultTrMinHeight },
|
|
1384
|
+
defaultTabWidth
|
|
1385
|
+
} = this.options
|
|
1386
|
+
const defaultBasicRowMarginHeight = this.getDefaultBasicRowMarginHeight()
|
|
1387
|
+
const canvas = document.createElement('canvas')
|
|
1388
|
+
const ctx = canvas.getContext('2d') as CanvasRenderingContext2D
|
|
1389
|
+
// 计算列表偏移宽度
|
|
1390
|
+
const listStyleMap = this.listParticle.computeListStyle(ctx, elementList)
|
|
1391
|
+
const rowList: IRow[] = []
|
|
1392
|
+
if (elementList.length) {
|
|
1393
|
+
rowList.push({
|
|
1394
|
+
width: 0,
|
|
1395
|
+
height: 0,
|
|
1396
|
+
ascent: 0,
|
|
1397
|
+
elementList: [],
|
|
1398
|
+
startIndex: 0,
|
|
1399
|
+
rowIndex: 0,
|
|
1400
|
+
rowFlex: elementList?.[0]?.rowFlex || elementList?.[1]?.rowFlex
|
|
1401
|
+
})
|
|
1402
|
+
}
|
|
1403
|
+
// 起始位置及页码计算
|
|
1404
|
+
let x = startX
|
|
1405
|
+
let y = startY
|
|
1406
|
+
let pageNo = 0
|
|
1407
|
+
// 列表位置
|
|
1408
|
+
let listId: string | undefined
|
|
1409
|
+
let listIndex = 0
|
|
1410
|
+
// 控件最小宽度
|
|
1411
|
+
let controlRealWidth = 0
|
|
1412
|
+
for (let i = 0; i < elementList.length; i++) {
|
|
1413
|
+
const curRow: IRow = rowList[rowList.length - 1]
|
|
1414
|
+
const element = elementList[i]
|
|
1415
|
+
const rowMargin = this.getElementRowMargin(element)
|
|
1416
|
+
const metrics: IElementMetrics = {
|
|
1417
|
+
width: 0,
|
|
1418
|
+
height: 0,
|
|
1419
|
+
boundingBoxAscent: 0,
|
|
1420
|
+
boundingBoxDescent: 0
|
|
1421
|
+
}
|
|
1422
|
+
// 实际可用宽度
|
|
1423
|
+
const offsetX =
|
|
1424
|
+
curRow.offsetX ||
|
|
1425
|
+
(element.listId && listStyleMap.get(element.listId)) ||
|
|
1426
|
+
0
|
|
1427
|
+
const availableWidth = innerWidth - offsetX
|
|
1428
|
+
// 增加起始位置坐标偏移量
|
|
1429
|
+
const isStartElement = curRow.elementList.length === 1
|
|
1430
|
+
x += isStartElement ? offsetX : 0
|
|
1431
|
+
y += isStartElement ? curRow.offsetY || 0 : 0
|
|
1432
|
+
if (
|
|
1433
|
+
(element.hide || element.control?.hide || element.area?.hide) &&
|
|
1434
|
+
!this.isDesignMode()
|
|
1435
|
+
) {
|
|
1436
|
+
const preElement = curRow.elementList[curRow.elementList.length - 1]
|
|
1437
|
+
metrics.height =
|
|
1438
|
+
preElement?.metrics.height || this.options.defaultSize * scale
|
|
1439
|
+
metrics.boundingBoxAscent = preElement?.metrics.boundingBoxAscent || 0
|
|
1440
|
+
metrics.boundingBoxDescent = preElement?.metrics.boundingBoxDescent || 0
|
|
1441
|
+
} else if (
|
|
1442
|
+
element.type === ElementType.IMAGE ||
|
|
1443
|
+
element.type === ElementType.LATEX
|
|
1444
|
+
) {
|
|
1445
|
+
// 浮动图片无需计算数据
|
|
1446
|
+
if (
|
|
1447
|
+
element.imgDisplay === ImageDisplay.SURROUND ||
|
|
1448
|
+
element.imgDisplay === ImageDisplay.FLOAT_TOP ||
|
|
1449
|
+
element.imgDisplay === ImageDisplay.FLOAT_BOTTOM
|
|
1450
|
+
) {
|
|
1451
|
+
metrics.width = 0
|
|
1452
|
+
metrics.height = 0
|
|
1453
|
+
metrics.boundingBoxDescent = 0
|
|
1454
|
+
} else {
|
|
1455
|
+
const elementWidth = element.width! * scale
|
|
1456
|
+
const elementHeight = element.height! * scale
|
|
1457
|
+
// 图片超出尺寸后自适应(图片大小大于可用宽度时)
|
|
1458
|
+
if (elementWidth > availableWidth) {
|
|
1459
|
+
const adaptiveHeight =
|
|
1460
|
+
(elementHeight * availableWidth) / elementWidth
|
|
1461
|
+
element.width = availableWidth / scale
|
|
1462
|
+
element.height = adaptiveHeight / scale
|
|
1463
|
+
metrics.width = availableWidth
|
|
1464
|
+
metrics.height = adaptiveHeight
|
|
1465
|
+
metrics.boundingBoxDescent = adaptiveHeight
|
|
1466
|
+
} else {
|
|
1467
|
+
metrics.width = elementWidth
|
|
1468
|
+
metrics.height = elementHeight
|
|
1469
|
+
metrics.boundingBoxDescent = elementHeight
|
|
1470
|
+
}
|
|
1471
|
+
// 增加题注高度
|
|
1472
|
+
if (element.imgCaption?.value) {
|
|
1473
|
+
const fontSize = element.imgCaption.size || imgCaption.size
|
|
1474
|
+
const captionTop = element.imgCaption.top ?? imgCaption.top
|
|
1475
|
+
const captionHeight = (fontSize + captionTop) * scale
|
|
1476
|
+
metrics.boundingBoxAscent += captionHeight
|
|
1477
|
+
}
|
|
1478
|
+
}
|
|
1479
|
+
} else if (element.type === ElementType.TABLE) {
|
|
1480
|
+
const tdPaddingWidth = tdPadding[1] + tdPadding[3]
|
|
1481
|
+
const tdPaddingHeight = tdPadding[0] + tdPadding[2]
|
|
1482
|
+
// 表格分页处理进度:https://github.com/Hufe921/canvas-editor/issues/41
|
|
1483
|
+
// 查看后续表格是否属于同一个源表格-存在即合并
|
|
1484
|
+
if (element.pagingId) {
|
|
1485
|
+
let tableIndex = i + 1
|
|
1486
|
+
let combineCount = 0
|
|
1487
|
+
while (tableIndex < elementList.length) {
|
|
1488
|
+
const nextElement = elementList[tableIndex]
|
|
1489
|
+
if (nextElement.pagingId === element.pagingId) {
|
|
1490
|
+
const nexTrList = nextElement.trList!.filter(
|
|
1491
|
+
tr => !tr.pagingRepeat
|
|
1492
|
+
)
|
|
1493
|
+
element.trList!.push(...nexTrList)
|
|
1494
|
+
element.height! += nextElement.height!
|
|
1495
|
+
tableIndex++
|
|
1496
|
+
combineCount++
|
|
1497
|
+
} else {
|
|
1498
|
+
break
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
if (combineCount) {
|
|
1502
|
+
elementList.splice(i + 1, combineCount)
|
|
1503
|
+
}
|
|
1504
|
+
}
|
|
1505
|
+
element.pagingIndex = element.pagingIndex ?? 0
|
|
1506
|
+
const trList = element.trList!
|
|
1507
|
+
// 计算前移除上一次的高度
|
|
1508
|
+
for (let t = 0; t < trList.length; t++) {
|
|
1509
|
+
const tr = trList[t]
|
|
1510
|
+
tr.height = tr.minHeight || defaultTrMinHeight
|
|
1511
|
+
tr.minHeight = tr.height
|
|
1512
|
+
}
|
|
1513
|
+
// 计算表格行列
|
|
1514
|
+
this.tableParticle.computeRowColInfo(element)
|
|
1515
|
+
// 计算表格内元素信息
|
|
1516
|
+
for (let t = 0; t < trList.length; t++) {
|
|
1517
|
+
const tr = trList[t]
|
|
1518
|
+
for (let d = 0; d < tr.tdList.length; d++) {
|
|
1519
|
+
const td = tr.tdList[d]
|
|
1520
|
+
const rowList = this.computeRowList({
|
|
1521
|
+
innerWidth: (td.width! - tdPaddingWidth) * scale,
|
|
1522
|
+
elementList: td.value,
|
|
1523
|
+
isFromTable: true,
|
|
1524
|
+
isPagingMode
|
|
1525
|
+
})
|
|
1526
|
+
const rowHeight = rowList.reduce((pre, cur) => pre + cur.height, 0)
|
|
1527
|
+
td.rowList = rowList
|
|
1528
|
+
// 移除缩放导致的行高变化-渲染时会进行缩放调整
|
|
1529
|
+
const curTdHeight = rowHeight / scale + tdPaddingHeight
|
|
1530
|
+
// 内容高度大于当前单元格高度需增加
|
|
1531
|
+
if (td.height! < curTdHeight) {
|
|
1532
|
+
const extraHeight = curTdHeight - td.height!
|
|
1533
|
+
const changeTr = trList[t + td.rowspan - 1]
|
|
1534
|
+
changeTr.height += extraHeight
|
|
1535
|
+
changeTr.tdList.forEach(changeTd => {
|
|
1536
|
+
changeTd.height! += extraHeight
|
|
1537
|
+
if (!changeTd.realHeight) {
|
|
1538
|
+
changeTd.realHeight = changeTd.height!
|
|
1539
|
+
} else {
|
|
1540
|
+
changeTd.realHeight! += extraHeight
|
|
1541
|
+
}
|
|
1542
|
+
})
|
|
1543
|
+
}
|
|
1544
|
+
// 当前单元格最小高度及真实高度(包含跨列)
|
|
1545
|
+
let curTdMinHeight = 0
|
|
1546
|
+
let curTdRealHeight = 0
|
|
1547
|
+
let i = 0
|
|
1548
|
+
while (i < td.rowspan) {
|
|
1549
|
+
const curTr = trList[i + t] || trList[t]
|
|
1550
|
+
curTdMinHeight += curTr.minHeight!
|
|
1551
|
+
curTdRealHeight += curTr.height!
|
|
1552
|
+
i++
|
|
1553
|
+
}
|
|
1554
|
+
td.realMinHeight = curTdMinHeight
|
|
1555
|
+
td.realHeight = curTdRealHeight
|
|
1556
|
+
td.mainHeight = curTdHeight
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
// 单元格高度大于实际内容高度需减少
|
|
1560
|
+
const reduceTrList = this.tableParticle.getTrListGroupByCol(trList)
|
|
1561
|
+
for (let t = 0; t < reduceTrList.length; t++) {
|
|
1562
|
+
const tr = reduceTrList[t]
|
|
1563
|
+
let reduceHeight = -1
|
|
1564
|
+
for (let d = 0; d < tr.tdList.length; d++) {
|
|
1565
|
+
const td = tr.tdList[d]
|
|
1566
|
+
const curTdRealHeight = td.realHeight!
|
|
1567
|
+
const curTdHeight = td.mainHeight!
|
|
1568
|
+
const curTdMinHeight = td.realMinHeight!
|
|
1569
|
+
// 获取最大可减少高度
|
|
1570
|
+
const curReduceHeight =
|
|
1571
|
+
curTdHeight < curTdMinHeight
|
|
1572
|
+
? curTdRealHeight - curTdMinHeight
|
|
1573
|
+
: curTdRealHeight - curTdHeight
|
|
1574
|
+
if (!~reduceHeight || curReduceHeight < reduceHeight) {
|
|
1575
|
+
reduceHeight = curReduceHeight
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
if (reduceHeight > 0) {
|
|
1579
|
+
const changeTr = trList[t]
|
|
1580
|
+
changeTr.height -= reduceHeight
|
|
1581
|
+
changeTr.tdList.forEach(changeTd => {
|
|
1582
|
+
changeTd.height! -= reduceHeight
|
|
1583
|
+
changeTd.realHeight! -= reduceHeight
|
|
1584
|
+
})
|
|
1585
|
+
}
|
|
1586
|
+
}
|
|
1587
|
+
// 需要重新计算表格内值
|
|
1588
|
+
this.tableParticle.computeRowColInfo(element)
|
|
1589
|
+
// 计算出表格高度
|
|
1590
|
+
const tableHeight = this.tableParticle.getTableHeight(element)
|
|
1591
|
+
const tableWidth = this.tableParticle.getTableWidth(element)
|
|
1592
|
+
element.width = tableWidth
|
|
1593
|
+
element.height = tableHeight
|
|
1594
|
+
const elementWidth = tableWidth * scale
|
|
1595
|
+
const elementHeight = tableHeight * scale
|
|
1596
|
+
metrics.width = elementWidth
|
|
1597
|
+
metrics.height = elementHeight
|
|
1598
|
+
metrics.boundingBoxDescent = elementHeight
|
|
1599
|
+
metrics.boundingBoxAscent = -rowMargin
|
|
1600
|
+
// 后一个元素也是表格则移除行间距
|
|
1601
|
+
if (elementList[i + 1]?.type === ElementType.TABLE) {
|
|
1602
|
+
metrics.boundingBoxAscent -= rowMargin
|
|
1603
|
+
}
|
|
1604
|
+
// 表格分页处理(拆分表格)
|
|
1605
|
+
if (isPagingMode) {
|
|
1606
|
+
const height = this.getHeight()
|
|
1607
|
+
const marginHeight = this.getMainOuterHeight()
|
|
1608
|
+
let curPagePreHeight = marginHeight
|
|
1609
|
+
for (let r = 0; r < rowList.length; r++) {
|
|
1610
|
+
const row = rowList[r]
|
|
1611
|
+
const rowOffsetY = row.offsetY || 0
|
|
1612
|
+
if (
|
|
1613
|
+
row.height + curPagePreHeight + rowOffsetY > height ||
|
|
1614
|
+
rowList[r - 1]?.isPageBreak
|
|
1615
|
+
) {
|
|
1616
|
+
curPagePreHeight = marginHeight + row.height + rowOffsetY
|
|
1617
|
+
} else {
|
|
1618
|
+
curPagePreHeight += row.height + rowOffsetY
|
|
1619
|
+
}
|
|
1620
|
+
}
|
|
1621
|
+
// 当前剩余高度是否能容下当前表格第一行(可拆分)的高度,排除掉表头类型
|
|
1622
|
+
// 前面元素为换页符时重新计算高度
|
|
1623
|
+
const rowMarginHeight = rowMargin * 2 * scale
|
|
1624
|
+
const firstTrHeight = element.trList![0].height! * scale
|
|
1625
|
+
if (
|
|
1626
|
+
curPagePreHeight + firstTrHeight + rowMarginHeight > height ||
|
|
1627
|
+
(element.pagingIndex !== 0 && element.trList![0].pagingRepeat) ||
|
|
1628
|
+
elementList[i - 1]?.type === ElementType.PAGE_BREAK
|
|
1629
|
+
) {
|
|
1630
|
+
// 无可拆分行则切换至新页
|
|
1631
|
+
curPagePreHeight = marginHeight
|
|
1632
|
+
}
|
|
1633
|
+
// 表格高度超过页面高度开始截断行
|
|
1634
|
+
if (curPagePreHeight + rowMarginHeight + elementHeight > height) {
|
|
1635
|
+
const trList = element.trList!
|
|
1636
|
+
// 计算需要移除的行数
|
|
1637
|
+
let deleteStart = 0
|
|
1638
|
+
let deleteCount = 0
|
|
1639
|
+
let preTrHeight = 0
|
|
1640
|
+
// 大于一行时再拆分避免循环
|
|
1641
|
+
if (trList.length > 1) {
|
|
1642
|
+
for (let r = 0; r < trList.length; r++) {
|
|
1643
|
+
const tr = trList[r]
|
|
1644
|
+
const trHeight = tr.height * scale
|
|
1645
|
+
if (
|
|
1646
|
+
curPagePreHeight + rowMarginHeight + preTrHeight + trHeight >
|
|
1647
|
+
height
|
|
1648
|
+
) {
|
|
1649
|
+
// 当前行存在跨行中断-暂时忽略分页
|
|
1650
|
+
const rowColCount = tr.tdList.reduce(
|
|
1651
|
+
(pre, cur) => pre + cur.colspan,
|
|
1652
|
+
0
|
|
1653
|
+
)
|
|
1654
|
+
if (element.colgroup?.length !== rowColCount) {
|
|
1655
|
+
deleteCount = 0
|
|
1656
|
+
}
|
|
1657
|
+
break
|
|
1658
|
+
} else {
|
|
1659
|
+
deleteStart = r + 1
|
|
1660
|
+
deleteCount = trList.length - deleteStart
|
|
1661
|
+
preTrHeight += trHeight
|
|
1662
|
+
}
|
|
1663
|
+
}
|
|
1664
|
+
}
|
|
1665
|
+
if (deleteCount) {
|
|
1666
|
+
const cloneTrList = trList.splice(deleteStart, deleteCount)
|
|
1667
|
+
const cloneTrHeight = cloneTrList.reduce(
|
|
1668
|
+
(pre, cur) => pre + cur.height,
|
|
1669
|
+
0
|
|
1670
|
+
)
|
|
1671
|
+
const cloneTrRealHeight = cloneTrHeight * scale
|
|
1672
|
+
const pagingId = element.pagingId || getUUID()
|
|
1673
|
+
element.pagingId = pagingId
|
|
1674
|
+
element.height -= cloneTrHeight
|
|
1675
|
+
metrics.height -= cloneTrRealHeight
|
|
1676
|
+
metrics.boundingBoxDescent -= cloneTrRealHeight
|
|
1677
|
+
// 追加拆分表格
|
|
1678
|
+
const cloneElement = deepClone(element)
|
|
1679
|
+
cloneElement.pagingId = pagingId
|
|
1680
|
+
cloneElement.pagingIndex = element.pagingIndex! + 1
|
|
1681
|
+
// 处理分页重复表头
|
|
1682
|
+
const repeatTrList = trList.filter(tr => tr.pagingRepeat)
|
|
1683
|
+
if (repeatTrList.length) {
|
|
1684
|
+
const cloneRepeatTrList = deepClone(repeatTrList)
|
|
1685
|
+
cloneRepeatTrList.forEach(tr => (tr.id = getUUID()))
|
|
1686
|
+
cloneTrList.unshift(...cloneRepeatTrList)
|
|
1687
|
+
}
|
|
1688
|
+
cloneElement.trList = cloneTrList
|
|
1689
|
+
cloneElement.id = getUUID()
|
|
1690
|
+
this.spliceElementList(elementList, i + 1, 0, [cloneElement])
|
|
1691
|
+
}
|
|
1692
|
+
}
|
|
1693
|
+
// 表格经过分页处理-需要处理上下文
|
|
1694
|
+
if (element.pagingId) {
|
|
1695
|
+
const positionContext = this.position.getPositionContext()
|
|
1696
|
+
if (positionContext.isTable) {
|
|
1697
|
+
// 查找光标所在表格索引(根据trId搜索)
|
|
1698
|
+
let newPositionContextIndex = -1
|
|
1699
|
+
let newPositionContextTrIndex = -1
|
|
1700
|
+
let tableIndex = i
|
|
1701
|
+
while (tableIndex < elementList.length) {
|
|
1702
|
+
const curElement = elementList[tableIndex]
|
|
1703
|
+
if (curElement.pagingId !== element.pagingId) break
|
|
1704
|
+
const trIndex = curElement.trList!.findIndex(
|
|
1705
|
+
r => r.id === positionContext.trId
|
|
1706
|
+
)
|
|
1707
|
+
if (~trIndex) {
|
|
1708
|
+
newPositionContextIndex = tableIndex
|
|
1709
|
+
newPositionContextTrIndex = trIndex
|
|
1710
|
+
break
|
|
1711
|
+
}
|
|
1712
|
+
tableIndex++
|
|
1713
|
+
}
|
|
1714
|
+
if (~newPositionContextIndex) {
|
|
1715
|
+
positionContext.index = newPositionContextIndex
|
|
1716
|
+
positionContext.trIndex = newPositionContextTrIndex
|
|
1717
|
+
this.position.setPositionContext(positionContext)
|
|
1718
|
+
}
|
|
1719
|
+
}
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
} else if (element.type === ElementType.SEPARATOR) {
|
|
1723
|
+
const {
|
|
1724
|
+
separator: { lineWidth: defaultLineWidth }
|
|
1725
|
+
} = this.options
|
|
1726
|
+
const lineWidth = element.lineWidth || defaultLineWidth
|
|
1727
|
+
element.width = availableWidth / scale
|
|
1728
|
+
metrics.width = availableWidth
|
|
1729
|
+
metrics.height = lineWidth * scale
|
|
1730
|
+
metrics.boundingBoxAscent = -rowMargin
|
|
1731
|
+
metrics.boundingBoxDescent = -rowMargin + metrics.height
|
|
1732
|
+
} else if (element.type === ElementType.PAGE_BREAK) {
|
|
1733
|
+
element.width = availableWidth / scale
|
|
1734
|
+
metrics.width = availableWidth
|
|
1735
|
+
metrics.height = defaultSize
|
|
1736
|
+
} else if (
|
|
1737
|
+
element.type === ElementType.RADIO ||
|
|
1738
|
+
element.controlComponent === ControlComponent.RADIO
|
|
1739
|
+
) {
|
|
1740
|
+
const { width, height, gap } = this.options.radio
|
|
1741
|
+
const elementWidth = width + gap * 2
|
|
1742
|
+
element.width = elementWidth
|
|
1743
|
+
metrics.width = elementWidth * scale
|
|
1744
|
+
metrics.height = height * scale
|
|
1745
|
+
} else if (
|
|
1746
|
+
element.type === ElementType.CHECKBOX ||
|
|
1747
|
+
element.controlComponent === ControlComponent.CHECKBOX
|
|
1748
|
+
) {
|
|
1749
|
+
const { width, height, gap } = this.options.checkbox
|
|
1750
|
+
const elementWidth = width + gap * 2
|
|
1751
|
+
element.width = elementWidth
|
|
1752
|
+
metrics.width = elementWidth * scale
|
|
1753
|
+
metrics.height = height * scale
|
|
1754
|
+
} else if (element.type === ElementType.TAB) {
|
|
1755
|
+
metrics.width = defaultTabWidth * scale
|
|
1756
|
+
metrics.height = defaultSize * scale
|
|
1757
|
+
metrics.boundingBoxDescent = 0
|
|
1758
|
+
metrics.boundingBoxAscent =
|
|
1759
|
+
this.textParticle.getBasisWordBoundingBoxAscent(ctx, ctx.font)
|
|
1760
|
+
} else if (element.type === ElementType.BLOCK) {
|
|
1761
|
+
if (!element.width) {
|
|
1762
|
+
metrics.width = availableWidth
|
|
1763
|
+
} else {
|
|
1764
|
+
const elementWidth = element.width * scale
|
|
1765
|
+
metrics.width = Math.min(elementWidth, availableWidth)
|
|
1766
|
+
}
|
|
1767
|
+
metrics.height = element.height! * scale
|
|
1768
|
+
metrics.boundingBoxDescent = metrics.height
|
|
1769
|
+
metrics.boundingBoxAscent = 0
|
|
1770
|
+
} else if (element.type === ElementType.LABEL) {
|
|
1771
|
+
const {
|
|
1772
|
+
defaultSize,
|
|
1773
|
+
label: { defaultPadding }
|
|
1774
|
+
} = this.options
|
|
1775
|
+
ctx.font = this.getElementFont(element)
|
|
1776
|
+
const fontMetrics = this.textParticle.measureText(ctx, element)
|
|
1777
|
+
metrics.width =
|
|
1778
|
+
(fontMetrics.width + defaultPadding[1] + defaultPadding[3]) * scale
|
|
1779
|
+
metrics.height = (element.size || defaultSize) * scale
|
|
1780
|
+
metrics.boundingBoxDescent = 0
|
|
1781
|
+
metrics.boundingBoxAscent =
|
|
1782
|
+
(defaultPadding[0] + fontMetrics.actualBoundingBoxAscent) * scale
|
|
1783
|
+
} else {
|
|
1784
|
+
// 设置上下标真实字体尺寸
|
|
1785
|
+
const size = element.size || defaultSize
|
|
1786
|
+
if (
|
|
1787
|
+
element.type === ElementType.SUPERSCRIPT ||
|
|
1788
|
+
element.type === ElementType.SUBSCRIPT
|
|
1789
|
+
) {
|
|
1790
|
+
element.actualSize = Math.ceil(size * 0.6)
|
|
1791
|
+
}
|
|
1792
|
+
metrics.height = (element.actualSize || size) * scale
|
|
1793
|
+
ctx.font = this.getElementFont(element)
|
|
1794
|
+
const fontMetrics = this.textParticle.measureText(ctx, element)
|
|
1795
|
+
metrics.width = fontMetrics.width * scale
|
|
1796
|
+
if (element.letterSpacing) {
|
|
1797
|
+
metrics.width += element.letterSpacing * scale
|
|
1798
|
+
}
|
|
1799
|
+
// 使用基于字体的基准度量以确保一致的行高,避免字符特定度量导致的布局跳动
|
|
1800
|
+
const basisMetrics = this.textParticle.measureBasisWord(
|
|
1801
|
+
ctx,
|
|
1802
|
+
element.font!
|
|
1803
|
+
)
|
|
1804
|
+
metrics.boundingBoxAscent = basisMetrics.actualBoundingBoxAscent * scale
|
|
1805
|
+
metrics.boundingBoxDescent =
|
|
1806
|
+
basisMetrics.actualBoundingBoxDescent * scale
|
|
1807
|
+
if (element.type === ElementType.SUPERSCRIPT) {
|
|
1808
|
+
metrics.boundingBoxAscent += metrics.height / 2
|
|
1809
|
+
} else if (element.type === ElementType.SUBSCRIPT) {
|
|
1810
|
+
metrics.boundingBoxDescent += metrics.height / 2
|
|
1811
|
+
}
|
|
1812
|
+
}
|
|
1813
|
+
const ascent =
|
|
1814
|
+
!element.hide &&
|
|
1815
|
+
((element.imgDisplay !== ImageDisplay.INLINE &&
|
|
1816
|
+
element.type === ElementType.IMAGE) ||
|
|
1817
|
+
element.type === ElementType.LATEX)
|
|
1818
|
+
? metrics.height + rowMargin
|
|
1819
|
+
: metrics.boundingBoxAscent + rowMargin
|
|
1820
|
+
const height =
|
|
1821
|
+
rowMargin +
|
|
1822
|
+
metrics.boundingBoxAscent +
|
|
1823
|
+
metrics.boundingBoxDescent +
|
|
1824
|
+
rowMargin
|
|
1825
|
+
const rowElement: IRowElement = Object.assign(element, {
|
|
1826
|
+
metrics,
|
|
1827
|
+
left: 0,
|
|
1828
|
+
style: this.getElementFont(element, scale)
|
|
1829
|
+
})
|
|
1830
|
+
// 暂时只考虑非换行场景:控件开始时统计宽度,结束时消费宽度及还原
|
|
1831
|
+
if (rowElement.control?.minWidth) {
|
|
1832
|
+
if (rowElement.controlComponent) {
|
|
1833
|
+
controlRealWidth += metrics.width
|
|
1834
|
+
}
|
|
1835
|
+
if (rowElement.controlComponent === ControlComponent.POSTFIX) {
|
|
1836
|
+
// 设置最小宽度控件属性(字符偏移量)
|
|
1837
|
+
this.control.setMinWidthControlInfo({
|
|
1838
|
+
row: curRow,
|
|
1839
|
+
rowElement,
|
|
1840
|
+
availableWidth,
|
|
1841
|
+
controlRealWidth
|
|
1842
|
+
})
|
|
1843
|
+
controlRealWidth = 0
|
|
1844
|
+
}
|
|
1845
|
+
}
|
|
1846
|
+
// 超过限定宽度
|
|
1847
|
+
const preElement = elementList[i - 1]
|
|
1848
|
+
let nextElement = elementList[i + 1]
|
|
1849
|
+
// 累计行宽 + 当前元素宽度 + 排版宽度(英文单词整体宽度 + 后面标点符号宽度)
|
|
1850
|
+
let curRowWidth = curRow.width + metrics.width
|
|
1851
|
+
if (this.options.wordBreak === WordBreak.BREAK_WORD) {
|
|
1852
|
+
if (
|
|
1853
|
+
(!preElement?.type || preElement?.type === ElementType.TEXT) &&
|
|
1854
|
+
(!element.type || element.type === ElementType.TEXT)
|
|
1855
|
+
) {
|
|
1856
|
+
// 英文单词
|
|
1857
|
+
const word = `${preElement?.value || ''}${element.value}`
|
|
1858
|
+
if (this.WORD_LIKE_REG.test(word)) {
|
|
1859
|
+
const { width, endElement } = this.textParticle.measureWord(
|
|
1860
|
+
ctx,
|
|
1861
|
+
elementList,
|
|
1862
|
+
i
|
|
1863
|
+
)
|
|
1864
|
+
// 后面存在元素 && 单词宽度大于行可用宽度,无需折行
|
|
1865
|
+
const wordWidth = width * scale
|
|
1866
|
+
if (endElement && wordWidth <= availableWidth) {
|
|
1867
|
+
curRowWidth += wordWidth
|
|
1868
|
+
nextElement = endElement
|
|
1869
|
+
}
|
|
1870
|
+
}
|
|
1871
|
+
// 标点符号
|
|
1872
|
+
const punctuationWidth = this.textParticle.measurePunctuationWidth(
|
|
1873
|
+
ctx,
|
|
1874
|
+
nextElement
|
|
1875
|
+
)
|
|
1876
|
+
curRowWidth += punctuationWidth * scale
|
|
1877
|
+
}
|
|
1878
|
+
}
|
|
1879
|
+
// 列表信息
|
|
1880
|
+
if (element.listId) {
|
|
1881
|
+
if (element.listId !== listId) {
|
|
1882
|
+
listIndex = 0
|
|
1883
|
+
} else if (element.value === ZERO && !element.listWrap) {
|
|
1884
|
+
listIndex++
|
|
1885
|
+
}
|
|
1886
|
+
}
|
|
1887
|
+
listId = element.listId
|
|
1888
|
+
// 计算四周环绕导致的元素偏移量
|
|
1889
|
+
const surroundPosition = this.position.setSurroundPosition({
|
|
1890
|
+
pageNo,
|
|
1891
|
+
rowElement,
|
|
1892
|
+
row: curRow,
|
|
1893
|
+
rowElementRect: {
|
|
1894
|
+
x,
|
|
1895
|
+
y,
|
|
1896
|
+
height,
|
|
1897
|
+
width: metrics.width
|
|
1898
|
+
},
|
|
1899
|
+
availableWidth,
|
|
1900
|
+
surroundElementList
|
|
1901
|
+
})
|
|
1902
|
+
x = surroundPosition.x
|
|
1903
|
+
curRowWidth += surroundPosition.rowIncreaseWidth
|
|
1904
|
+
x += metrics.width
|
|
1905
|
+
// 是否强制换行
|
|
1906
|
+
const isForceBreak =
|
|
1907
|
+
element.type === ElementType.SEPARATOR ||
|
|
1908
|
+
element.type === ElementType.TABLE ||
|
|
1909
|
+
preElement?.type === ElementType.TABLE ||
|
|
1910
|
+
preElement?.type === ElementType.BLOCK ||
|
|
1911
|
+
element.type === ElementType.BLOCK ||
|
|
1912
|
+
preElement?.imgDisplay === ImageDisplay.INLINE ||
|
|
1913
|
+
element.imgDisplay === ImageDisplay.INLINE ||
|
|
1914
|
+
preElement?.listId !== element.listId ||
|
|
1915
|
+
(preElement?.areaId !== element.areaId && !element.area?.hide) ||
|
|
1916
|
+
(element.control?.flexDirection === FlexDirection.COLUMN &&
|
|
1917
|
+
(element.controlComponent === ControlComponent.CHECKBOX ||
|
|
1918
|
+
element.controlComponent === ControlComponent.RADIO) &&
|
|
1919
|
+
preElement?.controlComponent === ControlComponent.VALUE) ||
|
|
1920
|
+
(i !== 0 && element.value === ZERO && !element.area?.hide)
|
|
1921
|
+
// 是否宽度不足导致换行
|
|
1922
|
+
const isWidthNotEnough = curRowWidth > availableWidth
|
|
1923
|
+
const isWrap = isForceBreak || isWidthNotEnough
|
|
1924
|
+
// 新行数据处理
|
|
1925
|
+
if (isWrap) {
|
|
1926
|
+
const row: IRow = {
|
|
1927
|
+
width: metrics.width,
|
|
1928
|
+
height,
|
|
1929
|
+
startIndex: i,
|
|
1930
|
+
elementList: [rowElement],
|
|
1931
|
+
ascent,
|
|
1932
|
+
rowIndex: curRow.rowIndex + 1,
|
|
1933
|
+
rowFlex: elementList[i]?.rowFlex || elementList[i + 1]?.rowFlex,
|
|
1934
|
+
isPageBreak: element.type === ElementType.PAGE_BREAK
|
|
1935
|
+
}
|
|
1936
|
+
// 控件缩进
|
|
1937
|
+
if (
|
|
1938
|
+
rowElement.controlComponent !== ControlComponent.PREFIX &&
|
|
1939
|
+
rowElement.control?.indentation === ControlIndentation.VALUE_START
|
|
1940
|
+
) {
|
|
1941
|
+
// 查找到非前缀的第一个元素位置
|
|
1942
|
+
const preStartIndex = curRow.elementList.findIndex(
|
|
1943
|
+
el =>
|
|
1944
|
+
el.controlId === rowElement.controlId &&
|
|
1945
|
+
el.controlComponent !== ControlComponent.PREFIX
|
|
1946
|
+
)
|
|
1947
|
+
if (~preStartIndex) {
|
|
1948
|
+
const preRowPositionList = this.position.computeRowPosition({
|
|
1949
|
+
row: curRow,
|
|
1950
|
+
innerWidth: this.getInnerWidth()
|
|
1951
|
+
})
|
|
1952
|
+
const valueStartPosition = preRowPositionList[preStartIndex]
|
|
1953
|
+
if (valueStartPosition) {
|
|
1954
|
+
row.offsetX = valueStartPosition.coordinate.leftTop[0]
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
}
|
|
1958
|
+
// 列表缩进
|
|
1959
|
+
if (element.listId) {
|
|
1960
|
+
row.isList = true
|
|
1961
|
+
row.offsetX = listStyleMap.get(element.listId!)
|
|
1962
|
+
row.listIndex = listIndex
|
|
1963
|
+
}
|
|
1964
|
+
// Y轴偏移量
|
|
1965
|
+
row.offsetY =
|
|
1966
|
+
!isFromTable &&
|
|
1967
|
+
element.area?.top &&
|
|
1968
|
+
element.areaId !== elementList[i - 1]?.areaId
|
|
1969
|
+
? element.area.top * scale
|
|
1970
|
+
: 0
|
|
1971
|
+
rowList.push(row)
|
|
1972
|
+
} else {
|
|
1973
|
+
curRow.width += metrics.width
|
|
1974
|
+
// 减小块元素前第一行空行行高
|
|
1975
|
+
if (
|
|
1976
|
+
i === 0 &&
|
|
1977
|
+
(getIsBlockElement(elementList[1]) || !!elementList[1]?.areaId)
|
|
1978
|
+
) {
|
|
1979
|
+
curRow.height = defaultBasicRowMarginHeight
|
|
1980
|
+
curRow.ascent = defaultBasicRowMarginHeight
|
|
1981
|
+
} else if (curRow.height < height) {
|
|
1982
|
+
curRow.height = height
|
|
1983
|
+
curRow.ascent = ascent
|
|
1984
|
+
}
|
|
1985
|
+
curRow.elementList.push(rowElement)
|
|
1986
|
+
}
|
|
1987
|
+
// 行结束时逻辑
|
|
1988
|
+
if (isWrap || i === elementList.length - 1) {
|
|
1989
|
+
// 换行原因:宽度不足
|
|
1990
|
+
curRow.isWidthNotEnough = isWidthNotEnough && !isForceBreak
|
|
1991
|
+
// 两端对齐、分散对齐
|
|
1992
|
+
if (
|
|
1993
|
+
!curRow.isSurround &&
|
|
1994
|
+
(preElement?.rowFlex === RowFlex.JUSTIFY ||
|
|
1995
|
+
(preElement?.rowFlex === RowFlex.ALIGNMENT &&
|
|
1996
|
+
curRow.isWidthNotEnough))
|
|
1997
|
+
) {
|
|
1998
|
+
// 忽略换行符及尾部元素间隔设置
|
|
1999
|
+
const rowElementList =
|
|
2000
|
+
curRow.elementList[0]?.value === ZERO
|
|
2001
|
+
? curRow.elementList.slice(1)
|
|
2002
|
+
: curRow.elementList
|
|
2003
|
+
const gap =
|
|
2004
|
+
(availableWidth - curRow.width) / (rowElementList.length - 1)
|
|
2005
|
+
for (let e = 0; e < rowElementList.length - 1; e++) {
|
|
2006
|
+
const el = rowElementList[e]
|
|
2007
|
+
el.metrics.width += gap
|
|
2008
|
+
}
|
|
2009
|
+
curRow.width = availableWidth
|
|
2010
|
+
}
|
|
2011
|
+
}
|
|
2012
|
+
// 重新计算坐标、页码、下一行首行元素环绕交叉
|
|
2013
|
+
if (isWrap) {
|
|
2014
|
+
x = startX
|
|
2015
|
+
y += curRow.height
|
|
2016
|
+
if (
|
|
2017
|
+
isPagingMode &&
|
|
2018
|
+
!isFromTable &&
|
|
2019
|
+
pageHeight &&
|
|
2020
|
+
(y - startY + mainOuterHeight + height > pageHeight ||
|
|
2021
|
+
element.type === ElementType.PAGE_BREAK)
|
|
2022
|
+
) {
|
|
2023
|
+
y = startY
|
|
2024
|
+
// 删除多余四周环绕型元素
|
|
2025
|
+
deleteSurroundElementList(surroundElementList, pageNo)
|
|
2026
|
+
pageNo += 1
|
|
2027
|
+
}
|
|
2028
|
+
// 计算下一行第一个元素是否存在环绕交叉
|
|
2029
|
+
rowElement.left = 0
|
|
2030
|
+
const nextRow = rowList[rowList.length - 1]
|
|
2031
|
+
const surroundPosition = this.position.setSurroundPosition({
|
|
2032
|
+
pageNo,
|
|
2033
|
+
rowElement,
|
|
2034
|
+
row: nextRow,
|
|
2035
|
+
rowElementRect: {
|
|
2036
|
+
x,
|
|
2037
|
+
y,
|
|
2038
|
+
height,
|
|
2039
|
+
width: metrics.width
|
|
2040
|
+
},
|
|
2041
|
+
availableWidth,
|
|
2042
|
+
surroundElementList
|
|
2043
|
+
})
|
|
2044
|
+
x = surroundPosition.x
|
|
2045
|
+
x += metrics.width
|
|
2046
|
+
}
|
|
2047
|
+
}
|
|
2048
|
+
return rowList
|
|
2049
|
+
}
|
|
2050
|
+
|
|
2051
|
+
private _computePageList(): IRow[][] {
|
|
2052
|
+
const pageRowList: IRow[][] = [[]]
|
|
2053
|
+
const {
|
|
2054
|
+
pageMode,
|
|
2055
|
+
pageNumber: { maxPageNo }
|
|
2056
|
+
} = this.options
|
|
2057
|
+
const height = this.getHeight()
|
|
2058
|
+
const marginHeight = this.getMainOuterHeight()
|
|
2059
|
+
let pageHeight = marginHeight
|
|
2060
|
+
let pageNo = 0
|
|
2061
|
+
if (pageMode === PageMode.CONTINUITY) {
|
|
2062
|
+
pageRowList[0] = this.rowList
|
|
2063
|
+
// 重置高度
|
|
2064
|
+
pageHeight += this.rowList.reduce(
|
|
2065
|
+
(pre, cur) => pre + cur.height + (cur.offsetY || 0),
|
|
2066
|
+
0
|
|
2067
|
+
)
|
|
2068
|
+
const dpr = this.getPagePixelRatio()
|
|
2069
|
+
const pageDom = this.pageList[0]
|
|
2070
|
+
const pageDomHeight = Number(pageDom.style.height.replace('px', ''))
|
|
2071
|
+
if (pageHeight > pageDomHeight) {
|
|
2072
|
+
pageDom.style.height = `${pageHeight}px`
|
|
2073
|
+
pageDom.height = pageHeight * dpr
|
|
2074
|
+
} else {
|
|
2075
|
+
const reduceHeight = pageHeight < height ? height : pageHeight
|
|
2076
|
+
pageDom.style.height = `${reduceHeight}px`
|
|
2077
|
+
pageDom.height = reduceHeight * dpr
|
|
2078
|
+
}
|
|
2079
|
+
this._initPageContext(this.ctxList[0])
|
|
2080
|
+
} else {
|
|
2081
|
+
for (let i = 0; i < this.rowList.length; i++) {
|
|
2082
|
+
const row = this.rowList[i]
|
|
2083
|
+
const rowOffsetY = row.offsetY || 0
|
|
2084
|
+
if (
|
|
2085
|
+
row.height + rowOffsetY + pageHeight > height ||
|
|
2086
|
+
this.rowList[i - 1]?.isPageBreak
|
|
2087
|
+
) {
|
|
2088
|
+
if (Number.isInteger(maxPageNo) && pageNo >= maxPageNo!) {
|
|
2089
|
+
this.elementList = this.elementList.slice(0, row.startIndex)
|
|
2090
|
+
break
|
|
2091
|
+
}
|
|
2092
|
+
pageHeight = marginHeight + row.height + rowOffsetY
|
|
2093
|
+
pageRowList.push([row])
|
|
2094
|
+
pageNo++
|
|
2095
|
+
} else {
|
|
2096
|
+
pageHeight += row.height + rowOffsetY
|
|
2097
|
+
pageRowList[pageNo].push(row)
|
|
2098
|
+
}
|
|
2099
|
+
}
|
|
2100
|
+
}
|
|
2101
|
+
return pageRowList
|
|
2102
|
+
}
|
|
2103
|
+
|
|
2104
|
+
private _drawHighlight(
|
|
2105
|
+
ctx: CanvasRenderingContext2D,
|
|
2106
|
+
payload: IDrawRowPayload
|
|
2107
|
+
) {
|
|
2108
|
+
const { rowList, positionList, elementList } = payload
|
|
2109
|
+
const marginHeight = this.getDefaultBasicRowMarginHeight()
|
|
2110
|
+
const highlightMarginHeight = this.getHighlightMarginHeight()
|
|
2111
|
+
for (let i = 0; i < rowList.length; i++) {
|
|
2112
|
+
const curRow = rowList[i]
|
|
2113
|
+
for (let j = 0; j < curRow.elementList.length; j++) {
|
|
2114
|
+
const element = curRow.elementList[j]
|
|
2115
|
+
const preElement = curRow.elementList[j - 1]
|
|
2116
|
+
// 高亮配置:元素 > 控件配置
|
|
2117
|
+
const highlight =
|
|
2118
|
+
element.highlight ||
|
|
2119
|
+
this.control.getControlHighlight(elementList, curRow.startIndex + j)
|
|
2120
|
+
if (highlight) {
|
|
2121
|
+
// 高亮元素相连需立即绘制,并记录下一元素坐标
|
|
2122
|
+
if (
|
|
2123
|
+
preElement &&
|
|
2124
|
+
preElement.highlight &&
|
|
2125
|
+
preElement.highlight !== element.highlight
|
|
2126
|
+
) {
|
|
2127
|
+
this.highlight.render(ctx)
|
|
2128
|
+
}
|
|
2129
|
+
// 当前元素位置信息记录
|
|
2130
|
+
const {
|
|
2131
|
+
coordinate: {
|
|
2132
|
+
leftTop: [x, y]
|
|
2133
|
+
}
|
|
2134
|
+
} = positionList[curRow.startIndex + j]
|
|
2135
|
+
// 元素向左偏移量
|
|
2136
|
+
const offsetX = element.left || 0
|
|
2137
|
+
this.highlight.recordFillInfo(
|
|
2138
|
+
ctx,
|
|
2139
|
+
x - offsetX,
|
|
2140
|
+
y + marginHeight - highlightMarginHeight, // 先减去行margin,再加上高亮margin
|
|
2141
|
+
element.metrics.width + offsetX,
|
|
2142
|
+
curRow.height - 2 * marginHeight + 2 * highlightMarginHeight,
|
|
2143
|
+
highlight
|
|
2144
|
+
)
|
|
2145
|
+
} else if (preElement?.highlight) {
|
|
2146
|
+
// 之前是高亮元素,当前不是需立即绘制
|
|
2147
|
+
this.highlight.render(ctx)
|
|
2148
|
+
}
|
|
2149
|
+
}
|
|
2150
|
+
this.highlight.render(ctx)
|
|
2151
|
+
}
|
|
2152
|
+
}
|
|
2153
|
+
|
|
2154
|
+
public drawRow(ctx: CanvasRenderingContext2D, payload: IDrawRowPayload) {
|
|
2155
|
+
// 优先绘制高亮元素
|
|
2156
|
+
this._drawHighlight(ctx, payload)
|
|
2157
|
+
// 绘制元素、下划线、删除线、选区
|
|
2158
|
+
const {
|
|
2159
|
+
scale,
|
|
2160
|
+
table: { tdPadding },
|
|
2161
|
+
group,
|
|
2162
|
+
lineBreak,
|
|
2163
|
+
whiteSpace
|
|
2164
|
+
} = this.options
|
|
2165
|
+
const {
|
|
2166
|
+
rowList,
|
|
2167
|
+
pageNo,
|
|
2168
|
+
elementList,
|
|
2169
|
+
positionList,
|
|
2170
|
+
startIndex,
|
|
2171
|
+
zone,
|
|
2172
|
+
isDrawLineBreak = !lineBreak.disabled,
|
|
2173
|
+
isDrawWhiteSpace = !whiteSpace.disabled
|
|
2174
|
+
} = payload
|
|
2175
|
+
const isPrintMode = this.isPrintMode()
|
|
2176
|
+
const isGraffitiMode = this.isGraffitiMode()
|
|
2177
|
+
const { isCrossRowCol, tableId } = this.range.getRange()
|
|
2178
|
+
let index = startIndex
|
|
2179
|
+
for (let i = 0; i < rowList.length; i++) {
|
|
2180
|
+
const curRow = rowList[i]
|
|
2181
|
+
// 选区绘制记录
|
|
2182
|
+
const rangeRecord: IElementFillRect = {
|
|
2183
|
+
x: 0,
|
|
2184
|
+
y: 0,
|
|
2185
|
+
width: 0,
|
|
2186
|
+
height: 0
|
|
2187
|
+
}
|
|
2188
|
+
let tableRangeElement: IElement | null = null
|
|
2189
|
+
for (let j = 0; j < curRow.elementList.length; j++) {
|
|
2190
|
+
const element = curRow.elementList[j]
|
|
2191
|
+
const metrics = element.metrics
|
|
2192
|
+
// 当前元素位置信息
|
|
2193
|
+
const {
|
|
2194
|
+
ascent: offsetY,
|
|
2195
|
+
coordinate: {
|
|
2196
|
+
leftTop: [x, y]
|
|
2197
|
+
}
|
|
2198
|
+
} = positionList[curRow.startIndex + j]
|
|
2199
|
+
const preElement = curRow.elementList[j - 1]
|
|
2200
|
+
// 元素绘制
|
|
2201
|
+
if (
|
|
2202
|
+
(element.hide || element.control?.hide || element.area?.hide) &&
|
|
2203
|
+
!this.isDesignMode()
|
|
2204
|
+
) {
|
|
2205
|
+
// 控件隐藏时不绘制
|
|
2206
|
+
this.textParticle.complete()
|
|
2207
|
+
} else if (element.type === ElementType.IMAGE) {
|
|
2208
|
+
this.textParticle.complete()
|
|
2209
|
+
// 浮动图片单独绘制
|
|
2210
|
+
if (
|
|
2211
|
+
element.imgDisplay !== ImageDisplay.SURROUND &&
|
|
2212
|
+
element.imgDisplay !== ImageDisplay.FLOAT_TOP &&
|
|
2213
|
+
element.imgDisplay !== ImageDisplay.FLOAT_BOTTOM
|
|
2214
|
+
) {
|
|
2215
|
+
this.imageParticle.render(ctx, element, x, y + offsetY)
|
|
2216
|
+
}
|
|
2217
|
+
} else if (element.type === ElementType.LATEX) {
|
|
2218
|
+
this.textParticle.complete()
|
|
2219
|
+
this.laTexParticle.render(ctx, element, x, y + offsetY)
|
|
2220
|
+
} else if (element.type === ElementType.TABLE) {
|
|
2221
|
+
if (isCrossRowCol) {
|
|
2222
|
+
rangeRecord.x = x
|
|
2223
|
+
rangeRecord.y = y
|
|
2224
|
+
tableRangeElement = element
|
|
2225
|
+
}
|
|
2226
|
+
this.tableParticle.render(ctx, element, x, y)
|
|
2227
|
+
} else if (element.type === ElementType.HYPERLINK) {
|
|
2228
|
+
this.textParticle.complete()
|
|
2229
|
+
this.hyperlinkParticle.render(ctx, element, x, y + offsetY)
|
|
2230
|
+
} else if (element.type === ElementType.LABEL) {
|
|
2231
|
+
this.textParticle.complete()
|
|
2232
|
+
this.labelParticle.render(ctx, element, x, y + offsetY)
|
|
2233
|
+
} else if (element.type === ElementType.DATE) {
|
|
2234
|
+
const nextElement = curRow.elementList[j + 1]
|
|
2235
|
+
// 释放之前的
|
|
2236
|
+
if (!preElement || preElement.dateId !== element.dateId) {
|
|
2237
|
+
this.textParticle.complete()
|
|
2238
|
+
}
|
|
2239
|
+
this.textParticle.record(ctx, element, x, y + offsetY)
|
|
2240
|
+
if (!nextElement || nextElement.dateId !== element.dateId) {
|
|
2241
|
+
// 手动触发渲染
|
|
2242
|
+
this.textParticle.complete()
|
|
2243
|
+
}
|
|
2244
|
+
} else if (element.type === ElementType.SUPERSCRIPT) {
|
|
2245
|
+
this.textParticle.complete()
|
|
2246
|
+
this.superscriptParticle.render(ctx, element, x, y + offsetY)
|
|
2247
|
+
} else if (element.type === ElementType.SUBSCRIPT) {
|
|
2248
|
+
this.underline.render(ctx)
|
|
2249
|
+
this.textParticle.complete()
|
|
2250
|
+
this.subscriptParticle.render(ctx, element, x, y + offsetY)
|
|
2251
|
+
} else if (element.type === ElementType.SEPARATOR) {
|
|
2252
|
+
this.separatorParticle.render(ctx, element, x, y)
|
|
2253
|
+
} else if (element.type === ElementType.PAGE_BREAK) {
|
|
2254
|
+
if (this.mode !== EditorMode.CLEAN && !isPrintMode) {
|
|
2255
|
+
this.pageBreakParticle.render(ctx, element, x, y)
|
|
2256
|
+
}
|
|
2257
|
+
} else if (
|
|
2258
|
+
element.type === ElementType.CHECKBOX ||
|
|
2259
|
+
element.controlComponent === ControlComponent.CHECKBOX
|
|
2260
|
+
) {
|
|
2261
|
+
this.textParticle.complete()
|
|
2262
|
+
this.checkboxParticle.render({
|
|
2263
|
+
ctx,
|
|
2264
|
+
x,
|
|
2265
|
+
y: y + offsetY,
|
|
2266
|
+
index: j,
|
|
2267
|
+
row: curRow
|
|
2268
|
+
})
|
|
2269
|
+
} else if (
|
|
2270
|
+
element.type === ElementType.RADIO ||
|
|
2271
|
+
element.controlComponent === ControlComponent.RADIO
|
|
2272
|
+
) {
|
|
2273
|
+
this.textParticle.complete()
|
|
2274
|
+
this.radioParticle.render({
|
|
2275
|
+
ctx,
|
|
2276
|
+
x,
|
|
2277
|
+
y: y + offsetY,
|
|
2278
|
+
index: j,
|
|
2279
|
+
row: curRow
|
|
2280
|
+
})
|
|
2281
|
+
} else if (element.type === ElementType.TAB) {
|
|
2282
|
+
this.textParticle.complete()
|
|
2283
|
+
} else if (
|
|
2284
|
+
element.rowFlex === RowFlex.ALIGNMENT ||
|
|
2285
|
+
element.rowFlex === RowFlex.JUSTIFY
|
|
2286
|
+
) {
|
|
2287
|
+
// 如果是两端对齐,因canvas目前不支持letterSpacing需单独绘制文本
|
|
2288
|
+
this.textParticle.record(ctx, element, x, y + offsetY)
|
|
2289
|
+
this.textParticle.complete()
|
|
2290
|
+
} else if (element.type === ElementType.BLOCK) {
|
|
2291
|
+
this.textParticle.complete()
|
|
2292
|
+
this.blockParticle.render(ctx, pageNo, element, x, y + offsetY)
|
|
2293
|
+
} else {
|
|
2294
|
+
// 如果当前元素设置左偏移,则上一元素立即绘制
|
|
2295
|
+
if (element.left) {
|
|
2296
|
+
this.textParticle.complete()
|
|
2297
|
+
}
|
|
2298
|
+
this.textParticle.record(ctx, element, x, y + offsetY)
|
|
2299
|
+
// 如果设置字宽、字间距、标点符号(避免浏览器排版缩小间距)需单独绘制
|
|
2300
|
+
if (
|
|
2301
|
+
element.width ||
|
|
2302
|
+
element.letterSpacing ||
|
|
2303
|
+
PUNCTUATION_REG.test(element.value)
|
|
2304
|
+
) {
|
|
2305
|
+
this.textParticle.complete()
|
|
2306
|
+
}
|
|
2307
|
+
}
|
|
2308
|
+
// 换行符绘制
|
|
2309
|
+
if (
|
|
2310
|
+
isDrawLineBreak &&
|
|
2311
|
+
!isPrintMode &&
|
|
2312
|
+
this.mode !== EditorMode.CLEAN &&
|
|
2313
|
+
!curRow.isWidthNotEnough &&
|
|
2314
|
+
j === curRow.elementList.length - 1
|
|
2315
|
+
) {
|
|
2316
|
+
this.lineBreakParticle.render(ctx, element, x, y + curRow.height / 2)
|
|
2317
|
+
}
|
|
2318
|
+
// 空白符绘制
|
|
2319
|
+
if (isDrawWhiteSpace && WHITE_SPACE_REG.test(element.value)) {
|
|
2320
|
+
this.whiteSpaceParticle.render(ctx, element, x, y + curRow.height / 2)
|
|
2321
|
+
}
|
|
2322
|
+
// 边框绘制(目前仅支持控件)
|
|
2323
|
+
if (element.control?.border) {
|
|
2324
|
+
// 不同控件边框立刻绘制
|
|
2325
|
+
if (
|
|
2326
|
+
preElement?.control?.border &&
|
|
2327
|
+
preElement.controlId !== element.controlId
|
|
2328
|
+
) {
|
|
2329
|
+
this.control.drawBorder(ctx)
|
|
2330
|
+
}
|
|
2331
|
+
// 当前元素位置信息记录
|
|
2332
|
+
const rowMargin = this.getElementRowMargin(element)
|
|
2333
|
+
this.control.recordBorderInfo(
|
|
2334
|
+
x,
|
|
2335
|
+
y + rowMargin,
|
|
2336
|
+
element.metrics.width,
|
|
2337
|
+
curRow.height - 2 * rowMargin
|
|
2338
|
+
)
|
|
2339
|
+
} else if (preElement?.control?.border) {
|
|
2340
|
+
this.control.drawBorder(ctx)
|
|
2341
|
+
}
|
|
2342
|
+
// 下划线记录
|
|
2343
|
+
if (element.underline || element.control?.underline) {
|
|
2344
|
+
// 下标元素下划线单独绘制
|
|
2345
|
+
if (
|
|
2346
|
+
preElement?.type === ElementType.SUBSCRIPT &&
|
|
2347
|
+
element.type !== ElementType.SUBSCRIPT
|
|
2348
|
+
) {
|
|
2349
|
+
this.underline.render(ctx)
|
|
2350
|
+
}
|
|
2351
|
+
// 行间距
|
|
2352
|
+
const rowMargin = this.getElementRowMargin(element)
|
|
2353
|
+
// 元素向左偏移量
|
|
2354
|
+
const offsetX = element.left || 0
|
|
2355
|
+
// 下标元素y轴偏移值
|
|
2356
|
+
let offsetY = 0
|
|
2357
|
+
if (element.type === ElementType.SUBSCRIPT) {
|
|
2358
|
+
offsetY = this.subscriptParticle.getOffsetY(element)
|
|
2359
|
+
}
|
|
2360
|
+
// 占位符不参与颜色计算
|
|
2361
|
+
const color = element.control?.underline
|
|
2362
|
+
? this.options.underlineColor
|
|
2363
|
+
: element.color
|
|
2364
|
+
this.underline.recordFillInfo(
|
|
2365
|
+
ctx,
|
|
2366
|
+
x - offsetX,
|
|
2367
|
+
y + curRow.height - rowMargin + offsetY,
|
|
2368
|
+
metrics.width + offsetX,
|
|
2369
|
+
0,
|
|
2370
|
+
color,
|
|
2371
|
+
element.textDecoration?.style
|
|
2372
|
+
)
|
|
2373
|
+
} else if (preElement?.underline || preElement?.control?.underline) {
|
|
2374
|
+
this.underline.render(ctx)
|
|
2375
|
+
}
|
|
2376
|
+
// 删除线记录
|
|
2377
|
+
if (element.strikeout) {
|
|
2378
|
+
// 仅文本类元素支持删除线
|
|
2379
|
+
if (!element.type || TEXTLIKE_ELEMENT_TYPE.includes(element.type)) {
|
|
2380
|
+
// 字体大小不同时需立即绘制
|
|
2381
|
+
if (
|
|
2382
|
+
preElement &&
|
|
2383
|
+
((preElement.type === ElementType.SUBSCRIPT &&
|
|
2384
|
+
element.type !== ElementType.SUBSCRIPT) ||
|
|
2385
|
+
(preElement.type === ElementType.SUPERSCRIPT &&
|
|
2386
|
+
element.type !== ElementType.SUPERSCRIPT) ||
|
|
2387
|
+
this.getElementSize(preElement) !==
|
|
2388
|
+
this.getElementSize(element))
|
|
2389
|
+
) {
|
|
2390
|
+
this.strikeout.render(ctx)
|
|
2391
|
+
}
|
|
2392
|
+
// 基线文字测量信息
|
|
2393
|
+
const standardMetrics = this.textParticle.measureBasisWord(
|
|
2394
|
+
ctx,
|
|
2395
|
+
this.getElementFont(element)
|
|
2396
|
+
)
|
|
2397
|
+
// 文字渲染位置 + 基线文字下偏移量 - 一半文字高度
|
|
2398
|
+
let adjustY =
|
|
2399
|
+
y +
|
|
2400
|
+
offsetY +
|
|
2401
|
+
standardMetrics.actualBoundingBoxDescent * scale -
|
|
2402
|
+
metrics.height / 2
|
|
2403
|
+
// 上下标位置调整
|
|
2404
|
+
if (element.type === ElementType.SUBSCRIPT) {
|
|
2405
|
+
adjustY += this.subscriptParticle.getOffsetY(element)
|
|
2406
|
+
} else if (element.type === ElementType.SUPERSCRIPT) {
|
|
2407
|
+
adjustY += this.superscriptParticle.getOffsetY(element)
|
|
2408
|
+
}
|
|
2409
|
+
this.strikeout.recordFillInfo(ctx, x, adjustY, metrics.width)
|
|
2410
|
+
}
|
|
2411
|
+
} else if (preElement?.strikeout) {
|
|
2412
|
+
this.strikeout.render(ctx)
|
|
2413
|
+
}
|
|
2414
|
+
// 选区记录
|
|
2415
|
+
const {
|
|
2416
|
+
zone: currentZone,
|
|
2417
|
+
startIndex,
|
|
2418
|
+
endIndex
|
|
2419
|
+
} = this.range.getRange()
|
|
2420
|
+
if (
|
|
2421
|
+
currentZone === zone &&
|
|
2422
|
+
startIndex !== endIndex &&
|
|
2423
|
+
startIndex <= index &&
|
|
2424
|
+
index <= endIndex
|
|
2425
|
+
) {
|
|
2426
|
+
const positionContext = this.position.getPositionContext()
|
|
2427
|
+
// 表格需限定上下文
|
|
2428
|
+
if (
|
|
2429
|
+
(!positionContext.isTable && !element.tdId) ||
|
|
2430
|
+
positionContext.tdId === element.tdId
|
|
2431
|
+
) {
|
|
2432
|
+
// 从行尾开始-绘制最小宽度
|
|
2433
|
+
if (startIndex === index) {
|
|
2434
|
+
const nextElement = elementList[startIndex + 1]
|
|
2435
|
+
if (nextElement && nextElement.value === ZERO) {
|
|
2436
|
+
rangeRecord.x = x + metrics.width
|
|
2437
|
+
rangeRecord.y = y
|
|
2438
|
+
rangeRecord.height = curRow.height
|
|
2439
|
+
rangeRecord.width += this.options.rangeMinWidth
|
|
2440
|
+
}
|
|
2441
|
+
} else {
|
|
2442
|
+
let rangeWidth = metrics.width
|
|
2443
|
+
// 最小选区宽度
|
|
2444
|
+
if (rangeWidth === 0 && curRow.elementList.length === 1) {
|
|
2445
|
+
rangeWidth = this.options.rangeMinWidth
|
|
2446
|
+
}
|
|
2447
|
+
// 记录第一次位置、行高
|
|
2448
|
+
if (!rangeRecord.width) {
|
|
2449
|
+
rangeRecord.x = x
|
|
2450
|
+
rangeRecord.y = y
|
|
2451
|
+
rangeRecord.height = curRow.height
|
|
2452
|
+
}
|
|
2453
|
+
rangeRecord.width += rangeWidth
|
|
2454
|
+
}
|
|
2455
|
+
}
|
|
2456
|
+
}
|
|
2457
|
+
// 组信息记录
|
|
2458
|
+
if (!group.disabled && element.groupIds) {
|
|
2459
|
+
this.group.recordFillInfo(element, x, y, metrics.width, curRow.height)
|
|
2460
|
+
}
|
|
2461
|
+
index++
|
|
2462
|
+
// 绘制表格内元素
|
|
2463
|
+
if (element.type === ElementType.TABLE && !element.hide) {
|
|
2464
|
+
const tdPaddingWidth = tdPadding[1] + tdPadding[3]
|
|
2465
|
+
for (let t = 0; t < element.trList!.length; t++) {
|
|
2466
|
+
const tr = element.trList![t]
|
|
2467
|
+
for (let d = 0; d < tr.tdList!.length; d++) {
|
|
2468
|
+
const td = tr.tdList[d]
|
|
2469
|
+
this.drawRow(ctx, {
|
|
2470
|
+
elementList: td.value,
|
|
2471
|
+
positionList: td.positionList!,
|
|
2472
|
+
rowList: td.rowList!,
|
|
2473
|
+
pageNo,
|
|
2474
|
+
startIndex: 0,
|
|
2475
|
+
innerWidth: (td.width! - tdPaddingWidth) * scale,
|
|
2476
|
+
zone,
|
|
2477
|
+
isDrawLineBreak
|
|
2478
|
+
})
|
|
2479
|
+
}
|
|
2480
|
+
}
|
|
2481
|
+
}
|
|
2482
|
+
}
|
|
2483
|
+
// 绘制列表样式
|
|
2484
|
+
if (curRow.isList) {
|
|
2485
|
+
this.listParticle.drawListStyle(
|
|
2486
|
+
ctx,
|
|
2487
|
+
curRow,
|
|
2488
|
+
positionList[curRow.startIndex]
|
|
2489
|
+
)
|
|
2490
|
+
}
|
|
2491
|
+
// 绘制文字、边框、下划线、删除线
|
|
2492
|
+
this.textParticle.complete()
|
|
2493
|
+
this.control.drawBorder(ctx)
|
|
2494
|
+
this.underline.render(ctx)
|
|
2495
|
+
this.strikeout.render(ctx)
|
|
2496
|
+
// 绘制批注样式
|
|
2497
|
+
this.group.render(ctx)
|
|
2498
|
+
// 绘制选区
|
|
2499
|
+
if (!isPrintMode && !isGraffitiMode) {
|
|
2500
|
+
if (rangeRecord.width && rangeRecord.height) {
|
|
2501
|
+
const { x, y, width, height } = rangeRecord
|
|
2502
|
+
this.range.render(ctx, x, y, width, height)
|
|
2503
|
+
}
|
|
2504
|
+
if (
|
|
2505
|
+
isCrossRowCol &&
|
|
2506
|
+
tableRangeElement &&
|
|
2507
|
+
tableRangeElement.id === tableId
|
|
2508
|
+
) {
|
|
2509
|
+
const {
|
|
2510
|
+
coordinate: {
|
|
2511
|
+
leftTop: [x, y]
|
|
2512
|
+
}
|
|
2513
|
+
} = positionList[curRow.startIndex]
|
|
2514
|
+
this.tableParticle.drawRange(ctx, tableRangeElement, x, y)
|
|
2515
|
+
}
|
|
2516
|
+
}
|
|
2517
|
+
}
|
|
2518
|
+
}
|
|
2519
|
+
|
|
2520
|
+
private _drawFloat(
|
|
2521
|
+
ctx: CanvasRenderingContext2D,
|
|
2522
|
+
payload: IDrawFloatPayload
|
|
2523
|
+
) {
|
|
2524
|
+
const { scale } = this.options
|
|
2525
|
+
const floatPositionList = this.position.getFloatPositionList()
|
|
2526
|
+
const { imgDisplays, pageNo } = payload
|
|
2527
|
+
for (let e = 0; e < floatPositionList.length; e++) {
|
|
2528
|
+
const floatPosition = floatPositionList[e]
|
|
2529
|
+
const element = floatPosition.element
|
|
2530
|
+
if (
|
|
2531
|
+
(pageNo === floatPosition.pageNo ||
|
|
2532
|
+
floatPosition.zone === EditorZone.HEADER ||
|
|
2533
|
+
floatPosition.zone == EditorZone.FOOTER) &&
|
|
2534
|
+
element.imgDisplay &&
|
|
2535
|
+
imgDisplays.includes(element.imgDisplay) &&
|
|
2536
|
+
element.type === ElementType.IMAGE
|
|
2537
|
+
) {
|
|
2538
|
+
const imgFloatPosition = element.imgFloatPosition!
|
|
2539
|
+
this.imageParticle.render(
|
|
2540
|
+
ctx,
|
|
2541
|
+
element,
|
|
2542
|
+
imgFloatPosition.x * scale,
|
|
2543
|
+
imgFloatPosition.y * scale
|
|
2544
|
+
)
|
|
2545
|
+
}
|
|
2546
|
+
}
|
|
2547
|
+
}
|
|
2548
|
+
|
|
2549
|
+
private _clearPage(pageNo: number) {
|
|
2550
|
+
const ctx = this.ctxList[pageNo]
|
|
2551
|
+
const pageDom = this.pageList[pageNo]
|
|
2552
|
+
ctx.clearRect(
|
|
2553
|
+
0,
|
|
2554
|
+
0,
|
|
2555
|
+
Math.max(pageDom.width, this.getWidth()),
|
|
2556
|
+
Math.max(pageDom.height, this.getHeight())
|
|
2557
|
+
)
|
|
2558
|
+
this.blockParticle.clear()
|
|
2559
|
+
}
|
|
2560
|
+
|
|
2561
|
+
private _drawPage(payload: IDrawPagePayload) {
|
|
2562
|
+
const { elementList, positionList, rowList, pageNo } = payload
|
|
2563
|
+
const {
|
|
2564
|
+
inactiveAlpha,
|
|
2565
|
+
pageMode,
|
|
2566
|
+
header,
|
|
2567
|
+
footer,
|
|
2568
|
+
pageNumber,
|
|
2569
|
+
lineNumber,
|
|
2570
|
+
pageBorder
|
|
2571
|
+
} = this.options
|
|
2572
|
+
const isPrintMode = this.mode === EditorMode.PRINT
|
|
2573
|
+
const innerWidth = this.getInnerWidth()
|
|
2574
|
+
const ctx = this.ctxList[pageNo]
|
|
2575
|
+
// 判断当前激活区域-非正文区域时元素透明度降低
|
|
2576
|
+
ctx.globalAlpha = !this.zone.isMainActive() ? inactiveAlpha : 1
|
|
2577
|
+
this._clearPage(pageNo)
|
|
2578
|
+
// 绘制背景
|
|
2579
|
+
if (
|
|
2580
|
+
!isPrintMode ||
|
|
2581
|
+
!this.options.modeRule[EditorMode.PRINT]?.backgroundDisabled
|
|
2582
|
+
) {
|
|
2583
|
+
this.background.render(ctx, pageNo)
|
|
2584
|
+
}
|
|
2585
|
+
// 绘制区域
|
|
2586
|
+
if (!isPrintMode) {
|
|
2587
|
+
this.area.render(ctx, pageNo)
|
|
2588
|
+
}
|
|
2589
|
+
// 绘制水印
|
|
2590
|
+
if (pageMode !== PageMode.CONTINUITY && this.options.watermark.data) {
|
|
2591
|
+
this.waterMark.render(ctx, pageNo)
|
|
2592
|
+
}
|
|
2593
|
+
// 绘制页边距
|
|
2594
|
+
if (!isPrintMode) {
|
|
2595
|
+
this.margin.render(ctx, pageNo)
|
|
2596
|
+
}
|
|
2597
|
+
// 渲染衬于文字下方元素
|
|
2598
|
+
this._drawFloat(ctx, {
|
|
2599
|
+
pageNo,
|
|
2600
|
+
imgDisplays: [ImageDisplay.FLOAT_BOTTOM]
|
|
2601
|
+
})
|
|
2602
|
+
// 控件高亮
|
|
2603
|
+
if (!isPrintMode) {
|
|
2604
|
+
this.control.renderHighlightList(ctx, pageNo)
|
|
2605
|
+
}
|
|
2606
|
+
// 渲染元素
|
|
2607
|
+
const index = rowList[0]?.startIndex
|
|
2608
|
+
this.drawRow(ctx, {
|
|
2609
|
+
elementList,
|
|
2610
|
+
positionList,
|
|
2611
|
+
rowList,
|
|
2612
|
+
pageNo,
|
|
2613
|
+
startIndex: index,
|
|
2614
|
+
innerWidth,
|
|
2615
|
+
zone: EditorZone.MAIN
|
|
2616
|
+
})
|
|
2617
|
+
if (this.getIsPagingMode()) {
|
|
2618
|
+
// 绘制页眉
|
|
2619
|
+
if (!header.disabled) {
|
|
2620
|
+
this.header.render(ctx, pageNo)
|
|
2621
|
+
}
|
|
2622
|
+
// 绘制页码
|
|
2623
|
+
if (!pageNumber.disabled) {
|
|
2624
|
+
this.pageNumber.render(ctx, pageNo)
|
|
2625
|
+
}
|
|
2626
|
+
// 绘制页脚
|
|
2627
|
+
if (!footer.disabled) {
|
|
2628
|
+
this.footer.render(ctx, pageNo)
|
|
2629
|
+
}
|
|
2630
|
+
}
|
|
2631
|
+
// 渲染浮于文字上方元素
|
|
2632
|
+
this._drawFloat(ctx, {
|
|
2633
|
+
pageNo,
|
|
2634
|
+
imgDisplays: [ImageDisplay.FLOAT_TOP, ImageDisplay.SURROUND]
|
|
2635
|
+
})
|
|
2636
|
+
// 搜索匹配绘制
|
|
2637
|
+
if (!isPrintMode && this.search.getSearchKeyword()) {
|
|
2638
|
+
this.search.render(ctx, pageNo)
|
|
2639
|
+
}
|
|
2640
|
+
// 绘制空白占位符
|
|
2641
|
+
if (this.elementList.length <= 1 && !this.elementList[0]?.listId) {
|
|
2642
|
+
this.placeholder.render(ctx)
|
|
2643
|
+
}
|
|
2644
|
+
// 渲染行数
|
|
2645
|
+
if (!lineNumber.disabled) {
|
|
2646
|
+
this.lineNumber.render(ctx, pageNo)
|
|
2647
|
+
}
|
|
2648
|
+
// 绘制页面边框
|
|
2649
|
+
if (!pageBorder.disabled) {
|
|
2650
|
+
this.pageBorder.render(ctx)
|
|
2651
|
+
}
|
|
2652
|
+
// 绘制签章
|
|
2653
|
+
this.badge.render(ctx, pageNo)
|
|
2654
|
+
// 绘制涂鸦
|
|
2655
|
+
if (this.isGraffitiMode()) {
|
|
2656
|
+
this.graffiti.render(ctx, pageNo)
|
|
2657
|
+
}
|
|
2658
|
+
}
|
|
2659
|
+
|
|
2660
|
+
private _disconnectLazyRender() {
|
|
2661
|
+
this.lazyRenderIntersectionObserver?.disconnect()
|
|
2662
|
+
}
|
|
2663
|
+
|
|
2664
|
+
private _lazyRender() {
|
|
2665
|
+
const positionList = this.position.getOriginalMainPositionList()
|
|
2666
|
+
const elementList = this.getOriginalMainElementList()
|
|
2667
|
+
this._disconnectLazyRender()
|
|
2668
|
+
this.lazyRenderIntersectionObserver = new IntersectionObserver(entries => {
|
|
2669
|
+
entries.forEach(entry => {
|
|
2670
|
+
if (entry.isIntersecting) {
|
|
2671
|
+
const index = Number((<HTMLCanvasElement>entry.target).dataset.index)
|
|
2672
|
+
this._drawPage({
|
|
2673
|
+
elementList,
|
|
2674
|
+
positionList,
|
|
2675
|
+
rowList: this.pageRowList[index],
|
|
2676
|
+
pageNo: index
|
|
2677
|
+
})
|
|
2678
|
+
}
|
|
2679
|
+
})
|
|
2680
|
+
})
|
|
2681
|
+
this.pageList.forEach(el => {
|
|
2682
|
+
this.lazyRenderIntersectionObserver!.observe(el)
|
|
2683
|
+
})
|
|
2684
|
+
}
|
|
2685
|
+
|
|
2686
|
+
private _immediateRender() {
|
|
2687
|
+
const positionList = this.position.getOriginalMainPositionList()
|
|
2688
|
+
const elementList = this.getOriginalMainElementList()
|
|
2689
|
+
for (let i = 0; i < this.pageRowList.length; i++) {
|
|
2690
|
+
this._drawPage({
|
|
2691
|
+
elementList,
|
|
2692
|
+
positionList,
|
|
2693
|
+
rowList: this.pageRowList[i],
|
|
2694
|
+
pageNo: i
|
|
2695
|
+
})
|
|
2696
|
+
}
|
|
2697
|
+
}
|
|
2698
|
+
|
|
2699
|
+
public render(payload?: IDrawOption) {
|
|
2700
|
+
this.renderCount++
|
|
2701
|
+
const { header, footer } = this.options
|
|
2702
|
+
const {
|
|
2703
|
+
isSubmitHistory = true,
|
|
2704
|
+
isSetCursor = true,
|
|
2705
|
+
isCompute = true,
|
|
2706
|
+
isLazy = true,
|
|
2707
|
+
isInit = false,
|
|
2708
|
+
isSourceHistory = false,
|
|
2709
|
+
isFirstRender = false
|
|
2710
|
+
} = payload || {}
|
|
2711
|
+
let { curIndex } = payload || {}
|
|
2712
|
+
const innerWidth = this.getInnerWidth()
|
|
2713
|
+
const isPagingMode = this.getIsPagingMode()
|
|
2714
|
+
// 缓存当前页数信息
|
|
2715
|
+
const oldPageSize = this.pageRowList.length
|
|
2716
|
+
// 计算文档信息
|
|
2717
|
+
if (isCompute) {
|
|
2718
|
+
// 清空浮动元素位置信息
|
|
2719
|
+
this.position.setFloatPositionList([])
|
|
2720
|
+
if (isPagingMode) {
|
|
2721
|
+
// 页眉信息
|
|
2722
|
+
if (!header.disabled) {
|
|
2723
|
+
this.header.compute()
|
|
2724
|
+
}
|
|
2725
|
+
// 页脚信息
|
|
2726
|
+
if (!footer.disabled) {
|
|
2727
|
+
this.footer.compute()
|
|
2728
|
+
}
|
|
2729
|
+
}
|
|
2730
|
+
// 行信息
|
|
2731
|
+
const margins = this.getMargins()
|
|
2732
|
+
const pageHeight = this.getHeight()
|
|
2733
|
+
const extraHeight = this.header.getExtraHeight()
|
|
2734
|
+
const mainOuterHeight = this.getMainOuterHeight()
|
|
2735
|
+
const startX = margins[3]
|
|
2736
|
+
const startY = margins[0] + extraHeight
|
|
2737
|
+
const surroundElementList = pickSurroundElementList(this.elementList)
|
|
2738
|
+
this.rowList = this.computeRowList({
|
|
2739
|
+
startX,
|
|
2740
|
+
startY,
|
|
2741
|
+
pageHeight,
|
|
2742
|
+
mainOuterHeight,
|
|
2743
|
+
isPagingMode,
|
|
2744
|
+
innerWidth,
|
|
2745
|
+
surroundElementList,
|
|
2746
|
+
elementList: this.elementList
|
|
2747
|
+
})
|
|
2748
|
+
// 页面信息
|
|
2749
|
+
this.pageRowList = this._computePageList()
|
|
2750
|
+
// 位置信息
|
|
2751
|
+
this.position.computePositionList()
|
|
2752
|
+
// 区域信息
|
|
2753
|
+
this.area.compute()
|
|
2754
|
+
if (!this.isPrintMode()) {
|
|
2755
|
+
// 搜索信息
|
|
2756
|
+
const searchKeyword = this.search.getSearchKeyword()
|
|
2757
|
+
if (searchKeyword) {
|
|
2758
|
+
this.search.compute(searchKeyword)
|
|
2759
|
+
}
|
|
2760
|
+
// 控件关键词高亮
|
|
2761
|
+
this.control.computeHighlightList()
|
|
2762
|
+
}
|
|
2763
|
+
// 涂鸦信息
|
|
2764
|
+
if (this.isGraffitiMode()) {
|
|
2765
|
+
this.graffiti.compute()
|
|
2766
|
+
}
|
|
2767
|
+
}
|
|
2768
|
+
// 清除光标等副作用
|
|
2769
|
+
this.imageObserver.clearAll()
|
|
2770
|
+
this.cursor.recoveryCursor()
|
|
2771
|
+
// 创建纸张
|
|
2772
|
+
for (let i = 0; i < this.pageRowList.length; i++) {
|
|
2773
|
+
if (!this.pageList[i]) {
|
|
2774
|
+
this._createPage(i)
|
|
2775
|
+
}
|
|
2776
|
+
}
|
|
2777
|
+
// 移除多余页
|
|
2778
|
+
const curPageCount = this.pageRowList.length
|
|
2779
|
+
const prePageCount = this.pageList.length
|
|
2780
|
+
if (prePageCount > curPageCount) {
|
|
2781
|
+
const deleteCount = prePageCount - curPageCount
|
|
2782
|
+
this.ctxList.splice(curPageCount, deleteCount)
|
|
2783
|
+
this.pageList
|
|
2784
|
+
.splice(curPageCount, deleteCount)
|
|
2785
|
+
.forEach(page => page.remove())
|
|
2786
|
+
}
|
|
2787
|
+
// 绘制元素
|
|
2788
|
+
// 连续页因为有高度的变化会导致canvas渲染空白,需立即渲染,否则会出现闪动
|
|
2789
|
+
if (isLazy && isPagingMode) {
|
|
2790
|
+
this._lazyRender()
|
|
2791
|
+
} else {
|
|
2792
|
+
this._immediateRender()
|
|
2793
|
+
}
|
|
2794
|
+
// 光标重绘
|
|
2795
|
+
if (isSetCursor) {
|
|
2796
|
+
curIndex = this.setCursor(curIndex)
|
|
2797
|
+
} else if (this.range.getIsSelection()) {
|
|
2798
|
+
// 存在选区时仅定位避免事件无法捕获
|
|
2799
|
+
this.cursor.focus()
|
|
2800
|
+
}
|
|
2801
|
+
// 历史记录用于undo、redo(非首次渲染内容变更 || 第一次存在光标时)
|
|
2802
|
+
if (
|
|
2803
|
+
(isSubmitHistory && !isFirstRender) ||
|
|
2804
|
+
(curIndex !== undefined && this.historyManager.isStackEmpty())
|
|
2805
|
+
) {
|
|
2806
|
+
this.submitHistory(curIndex)
|
|
2807
|
+
}
|
|
2808
|
+
// 信息变动回调
|
|
2809
|
+
nextTick(() => {
|
|
2810
|
+
// 选区样式
|
|
2811
|
+
this.range.setRangeStyle()
|
|
2812
|
+
// 重新唤起弹窗类控件
|
|
2813
|
+
if (isCompute && this.control.getActiveControl()) {
|
|
2814
|
+
this.control.reAwakeControl()
|
|
2815
|
+
}
|
|
2816
|
+
// 表格工具重新渲染
|
|
2817
|
+
if (
|
|
2818
|
+
isCompute &&
|
|
2819
|
+
!this.isReadonly() &&
|
|
2820
|
+
this.position.getPositionContext().isTable
|
|
2821
|
+
) {
|
|
2822
|
+
this.tableTool.render()
|
|
2823
|
+
}
|
|
2824
|
+
// 页眉指示器重新渲染
|
|
2825
|
+
if (isCompute && !this.zone.isMainActive()) {
|
|
2826
|
+
this.zone.drawZoneIndicator()
|
|
2827
|
+
}
|
|
2828
|
+
// 页数改变
|
|
2829
|
+
if (oldPageSize !== this.pageRowList.length) {
|
|
2830
|
+
if (this.listener.pageSizeChange) {
|
|
2831
|
+
this.listener.pageSizeChange(this.pageRowList.length)
|
|
2832
|
+
}
|
|
2833
|
+
if (this.eventBus.isSubscribe('pageSizeChange')) {
|
|
2834
|
+
this.eventBus.emit('pageSizeChange', this.pageRowList.length)
|
|
2835
|
+
}
|
|
2836
|
+
}
|
|
2837
|
+
// 文档内容改变
|
|
2838
|
+
if ((isSubmitHistory || isSourceHistory) && !isInit) {
|
|
2839
|
+
if (this.listener.contentChange) {
|
|
2840
|
+
this.listener.contentChange()
|
|
2841
|
+
}
|
|
2842
|
+
if (this.eventBus.isSubscribe('contentChange')) {
|
|
2843
|
+
this.eventBus.emit('contentChange')
|
|
2844
|
+
}
|
|
2845
|
+
}
|
|
2846
|
+
})
|
|
2847
|
+
}
|
|
2848
|
+
|
|
2849
|
+
public setCursor(curIndex: number | undefined) {
|
|
2850
|
+
const positionContext = this.position.getPositionContext()
|
|
2851
|
+
const positionList = this.position.getPositionList()
|
|
2852
|
+
if (positionContext.isTable) {
|
|
2853
|
+
const { index, trIndex, tdIndex } = positionContext
|
|
2854
|
+
const elementList = this.getOriginalElementList()
|
|
2855
|
+
const tablePositionList =
|
|
2856
|
+
elementList[index!].trList?.[trIndex!].tdList[tdIndex!].positionList
|
|
2857
|
+
if (curIndex === undefined && tablePositionList) {
|
|
2858
|
+
curIndex = tablePositionList.length - 1
|
|
2859
|
+
}
|
|
2860
|
+
const tablePosition = tablePositionList?.[curIndex!]
|
|
2861
|
+
this.position.setCursorPosition(tablePosition || null)
|
|
2862
|
+
} else {
|
|
2863
|
+
this.position.setCursorPosition(
|
|
2864
|
+
curIndex !== undefined ? positionList[curIndex] : null
|
|
2865
|
+
)
|
|
2866
|
+
}
|
|
2867
|
+
// 定位到图片元素并且位置发生变化
|
|
2868
|
+
let isShowCursor = true
|
|
2869
|
+
if (
|
|
2870
|
+
curIndex !== undefined &&
|
|
2871
|
+
positionContext.isImage &&
|
|
2872
|
+
positionContext.isDirectHit
|
|
2873
|
+
) {
|
|
2874
|
+
const elementList = this.getElementList()
|
|
2875
|
+
const element = elementList[curIndex]
|
|
2876
|
+
if (IMAGE_ELEMENT_TYPE.includes(element.type!)) {
|
|
2877
|
+
isShowCursor = false
|
|
2878
|
+
const position = this.position.getCursorPosition()
|
|
2879
|
+
this.previewer.updateResizer(element, position)
|
|
2880
|
+
}
|
|
2881
|
+
}
|
|
2882
|
+
this.cursor.drawCursor({
|
|
2883
|
+
isShow: isShowCursor
|
|
2884
|
+
})
|
|
2885
|
+
return curIndex
|
|
2886
|
+
}
|
|
2887
|
+
|
|
2888
|
+
public submitHistory(curIndex: number | undefined) {
|
|
2889
|
+
const positionContext = this.position.getPositionContext()
|
|
2890
|
+
const oldElementList = getSlimCloneElementList(this.elementList)
|
|
2891
|
+
const oldHeaderElementList = getSlimCloneElementList(
|
|
2892
|
+
this.header.getElementList()
|
|
2893
|
+
)
|
|
2894
|
+
const oldFooterElementList = getSlimCloneElementList(
|
|
2895
|
+
this.footer.getElementList()
|
|
2896
|
+
)
|
|
2897
|
+
const oldRange = deepClone(this.range.getRange())
|
|
2898
|
+
const pageNo = this.pageNo
|
|
2899
|
+
const oldPositionContext = deepClone(positionContext)
|
|
2900
|
+
const zone = this.zone.getZone()
|
|
2901
|
+
this.historyManager.execute(() => {
|
|
2902
|
+
this.zone.setZone(zone)
|
|
2903
|
+
this.setPageNo(pageNo)
|
|
2904
|
+
this.position.setPositionContext(deepClone(oldPositionContext))
|
|
2905
|
+
this.header.setElementList(deepClone(oldHeaderElementList))
|
|
2906
|
+
this.footer.setElementList(deepClone(oldFooterElementList))
|
|
2907
|
+
this.elementList = deepClone(oldElementList)
|
|
2908
|
+
this.range.replaceRange(deepClone(oldRange))
|
|
2909
|
+
this.render({
|
|
2910
|
+
curIndex,
|
|
2911
|
+
isSubmitHistory: false,
|
|
2912
|
+
isSourceHistory: true
|
|
2913
|
+
})
|
|
2914
|
+
})
|
|
2915
|
+
}
|
|
2916
|
+
|
|
2917
|
+
public destroy() {
|
|
2918
|
+
this.container.remove()
|
|
2919
|
+
this.globalEvent.removeEvent()
|
|
2920
|
+
this.scrollObserver.removeEvent()
|
|
2921
|
+
this.selectionObserver.removeEvent()
|
|
2922
|
+
}
|
|
2923
|
+
|
|
2924
|
+
public clearSideEffect() {
|
|
2925
|
+
// 预览工具组件
|
|
2926
|
+
this.getPreviewer().clearResizer()
|
|
2927
|
+
// 表格工具组件
|
|
2928
|
+
this.getTableTool().dispose()
|
|
2929
|
+
// 超链接弹窗
|
|
2930
|
+
this.getHyperlinkParticle().clearHyperlinkPopup()
|
|
2931
|
+
// 日期控件
|
|
2932
|
+
this.getDateParticle().clearDatePicker()
|
|
2933
|
+
}
|
|
2934
|
+
}
|