feat:add continuity page mode

pr675
黄云飞 4 years ago
parent 7c37e84497
commit 361e4394f7

@ -197,6 +197,15 @@
<div class="editor" editor-component="main"></div> <div class="editor" editor-component="main"></div>
<div class="footer" editor-component="footer"> <div class="footer" editor-component="footer">
<div> <div>
<div class="page-mode">
<i></i>
<div class="options">
<ul>
<li data-page-mode="paging" class="active">分页</li>
<li data-page-mode="continuity">连页</li>
</ul>
</div>
</div>
<span>可见页码:<span class="page-no-list">1</span></span> <span>可见页码:<span class="page-no-list">1</span></span>
<span>页面:<span class="page-no">1</span>/<span class="page-size">1</span></span> <span>页面:<span class="page-no">1</span>/<span class="page-size">1</span></span>
</div> </div>

@ -0,0 +1 @@
<svg width="16" height="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><g fill="none" fill-rule="evenodd"><g transform="translate(2 1)"><rect stroke="#3D4757" x=".5" y=".5" width="11" height="8" rx="1"/><path fill="#3D4757" fill-rule="nonzero" d="M2 3h4v1H2zm0 2h8v1H2z"/></g><g fill="#3D4757" fill-rule="nonzero"><path d="M14 15h-1v-5H3v5H2V9h12v6z"/><path d="M4 12h4v1H4zm0 2h8v1H4z"/></g></g></svg>

After

Width:  |  Height:  |  Size: 413 B

@ -1,5 +1,5 @@
import { IElement } from '../..' import { IElement } from '../..'
import { EditorMode } from '../../dataset/enum/Editor' import { EditorMode, PageMode } from '../../dataset/enum/Editor'
import { RowFlex } from '../../dataset/enum/Row' import { RowFlex } from '../../dataset/enum/Row'
import { IDrawImagePayload, IPainterOptions } from '../../interface/Draw' import { IDrawImagePayload, IPainterOptions } from '../../interface/Draw'
import { IEditorResult } from '../../interface/Editor' import { IEditorResult } from '../../interface/Editor'
@ -57,6 +57,7 @@ export class Command {
private static print: Function private static print: Function
private static getImage: Function private static getImage: Function
private static getValue: Function private static getValue: Function
private static pageMode: Function
private static pageScaleRecovery: Function private static pageScaleRecovery: Function
private static pageScaleMinus: Function private static pageScaleMinus: Function
private static pageScaleAdd: Function private static pageScaleAdd: Function
@ -111,6 +112,7 @@ export class Command {
Command.print = adapt.print.bind(adapt) Command.print = adapt.print.bind(adapt)
Command.getImage = adapt.getImage.bind(adapt) Command.getImage = adapt.getImage.bind(adapt)
Command.getValue = adapt.getValue.bind(adapt) Command.getValue = adapt.getValue.bind(adapt)
Command.pageMode = adapt.pageMode.bind(adapt)
Command.pageScaleRecovery = adapt.pageScaleRecovery.bind(adapt) Command.pageScaleRecovery = adapt.pageScaleRecovery.bind(adapt)
Command.pageScaleMinus = adapt.pageScaleMinus.bind(adapt) Command.pageScaleMinus = adapt.pageScaleMinus.bind(adapt)
Command.pageScaleAdd = adapt.pageScaleAdd.bind(adapt) Command.pageScaleAdd = adapt.pageScaleAdd.bind(adapt)
@ -313,7 +315,11 @@ export class Command {
return Command.getValue() return Command.getValue()
} }
// 页面缩放 // 页面模式、页面缩放
public executePageMode(payload: PageMode) {
return Command.pageMode(payload)
}
public executePageScaleRecovery() { public executePageScaleRecovery() {
return Command.pageScaleRecovery() return Command.pageScaleRecovery()
} }

@ -2,7 +2,7 @@ import { WRAP, ZERO } from '../../dataset/constant/Common'
import { EDITOR_ELEMENT_STYLE_ATTR } from '../../dataset/constant/Element' import { EDITOR_ELEMENT_STYLE_ATTR } from '../../dataset/constant/Element'
import { defaultWatermarkOption } from '../../dataset/constant/Watermark' import { defaultWatermarkOption } from '../../dataset/constant/Watermark'
import { ControlComponent } from '../../dataset/enum/Control' import { ControlComponent } from '../../dataset/enum/Control'
import { EditorContext, EditorMode } from '../../dataset/enum/Editor' import { EditorContext, EditorMode, PageMode } from '../../dataset/enum/Editor'
import { ElementType } from '../../dataset/enum/Element' import { ElementType } from '../../dataset/enum/Element'
import { ElementStyleKey } from '../../dataset/enum/ElementStyle' import { ElementStyleKey } from '../../dataset/enum/ElementStyle'
import { RowFlex } from '../../dataset/enum/Row' import { RowFlex } from '../../dataset/enum/Row'
@ -1243,6 +1243,10 @@ export class CommandAdapt {
return this.draw.getValue() return this.draw.getValue()
} }
public pageMode(payload: PageMode) {
this.draw.setPageMode(payload)
}
public pageScaleRecovery() { public pageScaleRecovery() {
const { scale } = this.options const { scale } = this.options
if (scale !== 1) { if (scale !== 1) {

@ -34,7 +34,7 @@ import { SubscriptParticle } from './particle/Subscript'
import { SeparatorParticle } from './particle/Separator' import { SeparatorParticle } from './particle/Separator'
import { PageBreakParticle } from './particle/PageBreak' import { PageBreakParticle } from './particle/PageBreak'
import { Watermark } from './frame/Watermark' import { Watermark } from './frame/Watermark'
import { EditorMode } from '../../dataset/enum/Editor' import { EditorMode, PageMode } from '../../dataset/enum/Editor'
import { Control } from './control/Control' import { Control } from './control/Control'
import { zipElementList } from '../../utils/element' import { zipElementList } from '../../utils/element'
import { CheckboxParticle } from './particle/CheckboxParticle' import { CheckboxParticle } from './particle/CheckboxParticle'
@ -97,7 +97,7 @@ export class Draw {
this.pageList = [] this.pageList = []
this.ctxList = [] this.ctxList = []
this.pageNo = 0 this.pageNo = 0
this.mode = options.defaultMode this.mode = options.mode
this.options = options this.options = options
this.elementList = elementList this.elementList = elementList
this.listener = listener this.listener = listener
@ -168,6 +168,16 @@ export class Draw {
return Math.floor(this.options.height * this.options.scale) return Math.floor(this.options.height * this.options.scale)
} }
public getCanvasWidth(): number {
const page = this.getPage()
return page.width
}
public getCanvasHeight(): number {
const page = this.getPage()
return page.height
}
public getInnerWidth(): number { public getInnerWidth(): number {
const width = this.getWidth() const width = this.getWidth()
const margins = this.getMargins() const margins = this.getMargins()
@ -394,6 +404,26 @@ export class Draw {
}) })
} }
public setPageMode(payload: PageMode) {
if (!payload || this.options.pageMode === payload) return
this.options.pageMode = payload
// 纸张大小重置
if (payload === PageMode.PAGING) {
const { height } = this.options
const dpr = window.devicePixelRatio
const canvas = this.pageList[0]
canvas.style.height = `${height}px`
canvas.height = height * dpr
}
this.render({ isSubmitHistory: false, isSetCursor: false })
// 回调
setTimeout(() => {
if (this.listener.pageModeChange) {
this.listener.pageModeChange(payload)
}
})
}
public setPageScale(payload: number) { public setPageScale(payload: number) {
this.options.scale = payload this.options.scale = payload
const width = this.getWidth() const width = this.getWidth()
@ -855,12 +885,12 @@ export class Draw {
} }
private _drawPage(positionList: IElementPosition[], rowList: IRow[], pageNo: number) { private _drawPage(positionList: IElementPosition[], rowList: IRow[], pageNo: number) {
const width = this.getWidth() const { pageMode } = this.options
const height = this.getHeight()
const margins = this.getMargins() const margins = this.getMargins()
const innerWidth = this.getInnerWidth() const innerWidth = this.getInnerWidth()
const ctx = this.ctxList[pageNo] const ctx = this.ctxList[pageNo]
ctx.clearRect(0, 0, width, height) const pageDom = this.pageList[pageNo]
ctx.clearRect(0, 0, pageDom.width, pageDom.height)
// 绘制背景 // 绘制背景
this.background.render(ctx) this.background.render(ctx)
// 绘制页边距 // 绘制页边距
@ -891,12 +921,13 @@ export class Draw {
this.search.render(ctx, pageNo) this.search.render(ctx, pageNo)
} }
// 绘制水印 // 绘制水印
if (this.options.watermark.data) { if (pageMode !== PageMode.CONTINUITY && this.options.watermark.data) {
this.waterMark.render(ctx) this.waterMark.render(ctx)
} }
} }
public render(payload?: IDrawOption) { public render(payload?: IDrawOption) {
const { pageMode } = this.options
const { const {
isSubmitHistory = true, isSubmitHistory = true,
isSetCursor = true, isSetCursor = true,
@ -922,15 +953,32 @@ export class Draw {
let pageHeight = marginHeight let pageHeight = marginHeight
let pageNo = 0 let pageNo = 0
const pageRowList: IRow[][] = [[]] const pageRowList: IRow[][] = [[]]
for (let i = 0; i < this.rowList.length; i++) { if (pageMode === PageMode.CONTINUITY) {
const row = this.rowList[i] pageRowList[0] = this.rowList
if (row.height + pageHeight > height || this.rowList[i - 1]?.isPageBreak) { // 重置高度
pageHeight = marginHeight + row.height pageHeight += this.rowList.reduce((pre, cur) => pre + cur.height, 0)
pageRowList.push([row]) const dpr = window.devicePixelRatio
pageNo++ const pageDom = this.pageList[0]
const pageDomHeight = Number(pageDom.style.height.replace('px', ''))
if (pageHeight > pageDomHeight) {
pageDom.style.height = `${pageHeight}px`
pageDom.height = pageHeight * dpr
} else { } else {
pageHeight += row.height const reduceHeight = pageHeight < height ? height : pageHeight
pageRowList[pageNo].push(row) pageDom.style.height = `${reduceHeight}px`
pageDom.height = reduceHeight * dpr
}
} else {
for (let i = 0; i < this.rowList.length; i++) {
const row = this.rowList[i]
if (row.height + pageHeight > height || this.rowList[i - 1]?.isPageBreak) {
pageHeight = marginHeight + row.height
pageRowList.push([row])
pageNo++
} else {
pageHeight += row.height
pageRowList[pageNo].push(row)
}
} }
} }
// 绘制元素 // 绘制元素

@ -1,3 +1,4 @@
import { PageMode } from '../../../dataset/enum/Editor'
import { IEditorOption } from '../../../interface/Editor' import { IEditorOption } from '../../../interface/Editor'
import { Draw } from '../Draw' import { Draw } from '../Draw'
@ -12,9 +13,11 @@ export class Margin {
} }
public render(ctx: CanvasRenderingContext2D) { public render(ctx: CanvasRenderingContext2D) {
const { marginIndicatorColor } = this.options const { marginIndicatorColor, pageMode } = this.options
const width = this.draw.getWidth() const width = this.draw.getWidth()
const height = this.draw.getHeight() const height = pageMode === PageMode.CONTINUITY
? this.draw.getCanvasHeight()
: this.draw.getHeight()
const margins = this.draw.getMargins() const margins = this.draw.getMargins()
const marginIndicatorSize = this.draw.getMarginIndicatorSize() const marginIndicatorSize = this.draw.getMarginIndicatorSize()
ctx.save() ctx.save()

@ -1,3 +1,4 @@
import { PageMode } from '../../../dataset/enum/Editor'
import { IEditorOption } from '../../../interface/Editor' import { IEditorOption } from '../../../interface/Editor'
import { Draw } from '../Draw' import { Draw } from '../Draw'
@ -12,9 +13,11 @@ export class PageNumber {
} }
public render(ctx: CanvasRenderingContext2D, pageNo: number) { public render(ctx: CanvasRenderingContext2D, pageNo: number) {
const { pageNumberSize, pageNumberFont, scale } = this.options const { pageNumberSize, pageNumberFont, scale, pageMode } = this.options
const width = this.draw.getWidth() const width = this.draw.getWidth()
const height = this.draw.getHeight() const height = pageMode === PageMode.CONTINUITY
? this.draw.getCanvasHeight()
: this.draw.getHeight()
const pageNumberBottom = this.draw.getPageNumberBottom() const pageNumberBottom = this.draw.getPageNumberBottom()
ctx.save() ctx.save()
ctx.fillStyle = '#00000' ctx.fillStyle = '#00000'

@ -2,6 +2,7 @@ import {
IContentChange, IContentChange,
IControlChange, IControlChange,
IIntersectionPageNoChange, IIntersectionPageNoChange,
IPageModeChange,
IPageScaleChange, IPageScaleChange,
IPageSizeChange, IPageSizeChange,
IRangeStyleChange, IRangeStyleChange,
@ -19,6 +20,7 @@ export class Listener {
public saved: ISaved | null public saved: ISaved | null
public contentChange: IContentChange | null public contentChange: IContentChange | null
public controlChange: IControlChange | null public controlChange: IControlChange | null
public pageModeChange: IPageModeChange | null
constructor() { constructor() {
this.rangeStyleChange = null this.rangeStyleChange = null
@ -29,6 +31,7 @@ export class Listener {
this.saved = null this.saved = null
this.contentChange = null this.contentChange = null
this.controlChange = null this.controlChange = null
this.pageModeChange = null
} }
} }

@ -16,4 +16,9 @@ export enum EditorMode {
EDIT = 'edit', EDIT = 'edit',
CLEAN = 'clean', CLEAN = 'clean',
READONLY = 'readonly' READONLY = 'readonly'
}
export enum PageMode {
PAGING = 'paging',
CONTINUITY = 'continuity'
} }

@ -13,7 +13,7 @@ import { globalMenus } from './core/contextmenu/menus/globalMenus'
import { ContextMenu } from './core/contextmenu/ContextMenu' import { ContextMenu } from './core/contextmenu/ContextMenu'
import { tableMenus } from './core/contextmenu/menus/tableMenus' import { tableMenus } from './core/contextmenu/menus/tableMenus'
import { IContextMenuContext, IRegisterContextMenu } from './interface/contextmenu/ContextMenu' import { IContextMenuContext, IRegisterContextMenu } from './interface/contextmenu/ContextMenu'
import { EditorComponent, EditorMode } from './dataset/enum/Editor' import { EditorComponent, EditorMode, PageMode } from './dataset/enum/Editor'
import { EDITOR_COMPONENT } from './dataset/constant/Editor' import { EDITOR_COMPONENT } from './dataset/constant/Editor'
import { IHeader } from './interface/Header' import { IHeader } from './interface/Header'
import { IWatermark } from './interface/Watermark' import { IWatermark } from './interface/Watermark'
@ -51,7 +51,7 @@ export default class Editor {
} }
const editorOptions: DeepRequired<IEditorOption> = { const editorOptions: DeepRequired<IEditorOption> = {
defaultMode: EditorMode.EDIT, mode: EditorMode.EDIT,
defaultType: 'TEXT', defaultType: 'TEXT',
defaultFont: 'Yahei', defaultFont: 'Yahei',
defaultSize: 16, defaultSize: 16,
@ -77,6 +77,7 @@ export default class Editor {
marginIndicatorSize: 35, marginIndicatorSize: 35,
marginIndicatorColor: '#BABABA', marginIndicatorColor: '#BABABA',
margins: [100, 120, 100, 120], margins: [100, 120, 100, 120],
pageMode: PageMode.PAGING,
tdPadding: 5, tdPadding: 5,
defaultTdHeight: 40, defaultTdHeight: 40,
defaultHyperlinkColor: '#0000FF', defaultHyperlinkColor: '#0000FF',
@ -116,7 +117,8 @@ export {
ElementType, ElementType,
ControlType, ControlType,
EditorComponent, EditorComponent,
EDITOR_COMPONENT EDITOR_COMPONENT,
PageMode
} }
// 对外类型 // 对外类型

@ -1,12 +1,12 @@
import { IElement } from '..' import { IElement } from '..'
import { EditorMode } from '../dataset/enum/Editor' import { EditorMode, PageMode } from '../dataset/enum/Editor'
import { ICheckboxOption } from './Checkbox' import { ICheckboxOption } from './Checkbox'
import { IControlOption } from './Control' import { IControlOption } from './Control'
import { IHeader } from './Header' import { IHeader } from './Header'
import { IWatermark } from './Watermark' import { IWatermark } from './Watermark'
export interface IEditorOption { export interface IEditorOption {
defaultMode?: EditorMode; mode?: EditorMode;
defaultType?: string; defaultType?: string;
defaultFont?: string; defaultFont?: string;
defaultSize?: number; defaultSize?: number;
@ -32,6 +32,7 @@ export interface IEditorOption {
marginIndicatorSize?: number; marginIndicatorSize?: number;
marginIndicatorColor?: string, marginIndicatorColor?: string,
margins?: [top: number, right: number, bottom: number, left: number], margins?: [top: number, right: number, bottom: number, left: number],
pageMode?: PageMode;
tdPadding?: number; tdPadding?: number;
defaultTdHeight?: number; defaultTdHeight?: number;
defaultHyperlinkColor?: string; defaultHyperlinkColor?: string;

@ -1,4 +1,4 @@
import { ElementType } from '..' import { ElementType, PageMode } from '..'
import { RowFlex } from '../dataset/enum/Row' import { RowFlex } from '../dataset/enum/Row'
import { IControl } from './Control' import { IControl } from './Control'
import { IEditorResult } from './Editor' import { IEditorResult } from './Editor'
@ -34,4 +34,6 @@ export type ISaved = (payload: IEditorResult) => void
export type IContentChange = () => void export type IContentChange = () => void
export type IControlChange = (payload: IControl | null) => void export type IControlChange = (payload: IControl | null) => void
export type IPageModeChange = (payload: PageMode) => void

@ -1,7 +1,7 @@
import { data, options } from './mock' import { data, options } from './mock'
import './style.css' import './style.css'
import prism from 'prismjs' import prism from 'prismjs'
import Editor, { ControlType, EditorMode, ElementType, IElement } from './editor' import Editor, { ControlType, EditorMode, ElementType, IElement, PageMode } from './editor'
import { Dialog } from './components/dialog/Dialog' import { Dialog } from './components/dialog/Dialog'
import { formatPrismToken } from './utils/prism' import { formatPrismToken } from './utils/prism'
@ -586,7 +586,17 @@ window.onload = function () {
instance.command.executePrint() instance.command.executePrint()
} }
// 6. 纸张缩放 // 6. 页面模式 | 纸张缩放
const pageModeDom = document.querySelector<HTMLDivElement>('.page-mode')!
const pageModeOptionsDom = pageModeDom.querySelector<HTMLDivElement>('.options')!
pageModeDom.onclick = function () {
pageModeOptionsDom.classList.toggle('visible')
}
pageModeOptionsDom.onclick = function (evt) {
const li = evt.target as HTMLLIElement
instance.command.executePageMode(<PageMode>li.dataset.pageMode!)
}
document.querySelector<HTMLDivElement>('.page-scale-percentage')!.onclick = function () { document.querySelector<HTMLDivElement>('.page-scale-percentage')!.onclick = function () {
console.log('page-scale-recovery') console.log('page-scale-recovery')
instance.command.executePageScaleRecovery() instance.command.executePageScaleRecovery()
@ -738,6 +748,12 @@ window.onload = function () {
}) })
} }
instance.listener.pageModeChange = function (payload) {
const activeMode = pageModeOptionsDom.querySelector<HTMLLIElement>(`[data-page-mode='${payload}']`)!
pageModeOptionsDom.querySelectorAll('li').forEach(li => li.classList.remove('active'))
activeMode.classList.add('active')
}
instance.listener.saved = function (payload) { instance.listener.saved = function (payload) {
console.log('elementList: ', payload) console.log('elementList: ', payload)
} }

@ -551,7 +551,6 @@ ul {
justify-content: space-between; justify-content: space-between;
background: #f2f4f7; background: #f2f4f7;
z-index: 9; z-index: 9;
overflow: hidden;
position: fixed; position: fixed;
bottom: 0; bottom: 0;
left: 0; left: 0;
@ -560,6 +559,60 @@ ul {
box-sizing: border-box; box-sizing: border-box;
} }
.footer>div:first-child {
display: flex;
align-items: center;
}
.footer .page-mode {
padding: 1px;
position: relative;
}
.footer .page-mode i {
width: 16px;
height: 16px;
margin-right: 5px;
cursor: pointer;
display: inline-block;
background-image: url('./assets/images/page-mode.svg');
}
.footer .page-mode .options {
width: 70px;
position: absolute;
left: 0;
bottom: 25px;
padding: 10px;
background: #fff;
font-size: 14px;
box-shadow: 0 2px 12px 0 rgb(56 56 56 / 20%);
border: 1px solid #e2e6ed;
border-radius: 2px;
display: none;
}
.footer .page-mode .options.visible {
display: block;
}
.footer .page-mode .options li {
padding: 5px;
margin: 5px 0;
user-select: none;
transition: all .3s;
text-align: center;
cursor: pointer;
}
.footer .page-mode .options li:hover {
background-color: #ebecef;
}
.footer .page-mode .options li.active {
background-color: #e2e6ed;
}
.footer>div:first-child>span { .footer>div:first-child>span {
display: inline-block; display: inline-block;
margin-right: 5px; margin-right: 5px;

Loading…
Cancel
Save