diff --git a/index.html b/index.html
index 059867e..8b89f41 100644
--- a/index.html
+++ b/index.html
@@ -121,12 +121,12 @@
页面:1/1
-
diff --git a/src/assets/images/page-add.svg b/src/assets/images/page-scale-add.svg
similarity index 100%
rename from src/assets/images/page-add.svg
rename to src/assets/images/page-scale-add.svg
diff --git a/src/assets/images/page-minus.svg b/src/assets/images/page-scale-minus.svg
similarity index 100%
rename from src/assets/images/page-minus.svg
rename to src/assets/images/page-scale-minus.svg
diff --git a/src/editor/core/command/Command.ts b/src/editor/core/command/Command.ts
index acc8535..88bcfb5 100644
--- a/src/editor/core/command/Command.ts
+++ b/src/editor/core/command/Command.ts
@@ -24,6 +24,8 @@ export class Command {
private static image: Function
private static search: Function
private static print: Function
+ private static pageScaleMinus: Function
+ private static pageScaleAdd: Function
constructor(adapt: CommandAdapt) {
Command.undo = adapt.undo.bind(adapt)
@@ -46,6 +48,8 @@ export class Command {
Command.image = adapt.image.bind(adapt)
Command.search = adapt.search.bind(adapt)
Command.print = adapt.print.bind(adapt)
+ Command.pageScaleMinus = adapt.pageScaleMinus.bind(adapt)
+ Command.pageScaleAdd = adapt.pageScaleAdd.bind(adapt)
}
// 撤销、重做、格式刷、清除格式
@@ -131,4 +135,13 @@ export class Command {
return Command.print()
}
+ // 页面缩放
+ public executePageScaleMinus() {
+ return Command.pageScaleMinus()
+ }
+
+ public executePageScaleAdd() {
+ return Command.pageScaleAdd()
+ }
+
}
\ No newline at end of file
diff --git a/src/editor/core/command/CommandAdapt.ts b/src/editor/core/command/CommandAdapt.ts
index 23c013d..45c6102 100644
--- a/src/editor/core/command/CommandAdapt.ts
+++ b/src/editor/core/command/CommandAdapt.ts
@@ -262,4 +262,20 @@ export class CommandAdapt {
return printImageBase64(this.draw.getDataURL(), width, height)
}
+ public pageScaleMinus() {
+ const { scale } = this.options
+ const nextScale = scale * 10 - 1
+ if (nextScale >= 5) {
+ this.draw.setPageScale(nextScale / 10)
+ }
+ }
+
+ public pageScaleAdd() {
+ const { scale } = this.options
+ const nextScale = scale * 10 + 1
+ if (nextScale <= 30) {
+ this.draw.setPageScale(nextScale / 10)
+ }
+ }
+
}
\ No newline at end of file
diff --git a/src/editor/core/cursor/Cursor.ts b/src/editor/core/cursor/Cursor.ts
index 457fe6d..058c3e3 100644
--- a/src/editor/core/cursor/Cursor.ts
+++ b/src/editor/core/cursor/Cursor.ts
@@ -7,6 +7,7 @@ import { CursorAgent } from "./CursorAgent"
export class Cursor {
+ private draw: Draw
private container: HTMLDivElement
private options: Required
private position: Position
@@ -14,6 +15,7 @@ export class Cursor {
private cursorAgent: CursorAgent
constructor(draw: Draw, canvasEvent: CanvasEvent) {
+ this.draw = draw
this.container = draw.getContainer()
this.position = draw.getPosition()
this.options = draw.getOptions()
@@ -36,8 +38,10 @@ export class Cursor {
const cursorPosition = this.position.getCursorPosition()
if (!cursorPosition) return
// 设置光标代理
+ const { scale } = this.options
+ const height = this.draw.getHeight()
+ const pageGap = this.draw.getPageGap()
const { metrics, coordinate: { leftTop, rightTop }, ascent, pageNo } = cursorPosition
- const { height, pageGap } = this.options
const preY = pageNo * (height + pageGap)
// 增加1/4字体大小
const offsetHeight = metrics.height / 4
@@ -52,7 +56,7 @@ export class Cursor {
const cursorTop = (leftTop[1] + ascent) + descent - (cursorHeight - offsetHeight) + preY
const curosrleft = rightTop[0]
agentCursorDom.style.left = `${curosrleft}px`
- agentCursorDom.style.top = `${cursorTop + cursorHeight - CURSOR_AGENT_HEIGHT}px`
+ agentCursorDom.style.top = `${cursorTop + cursorHeight - CURSOR_AGENT_HEIGHT * scale}px`
// 模拟光标显示
this.cursorDom.style.left = `${curosrleft}px`
this.cursorDom.style.top = `${cursorTop}px`
diff --git a/src/editor/core/draw/Draw.ts b/src/editor/core/draw/Draw.ts
index 341ebfa..8580bc8 100644
--- a/src/editor/core/draw/Draw.ts
+++ b/src/editor/core/draw/Draw.ts
@@ -49,7 +49,6 @@ export class Draw {
private textParticle: TextParticle
private pageNumber: PageNumber
- private innerWidth: number
private rowList: IRow[]
private painterStyle: IElementStyle | null
private searchMatchList: number[][] | null
@@ -93,8 +92,6 @@ export class Draw {
const globalEvent = new GlobalEvent(this, canvasEvent)
globalEvent.register()
- const { width, margins } = options
- this.innerWidth = width - margins[1] - margins[3]
this.rowList = []
this.painterStyle = null
this.searchMatchList = null
@@ -104,6 +101,40 @@ export class Draw {
this.render({ isSetCursor: false })
}
+ public getWidth(): number {
+ return Math.floor(this.options.width * this.options.scale)
+ }
+
+ public getHeight(): number {
+ return Math.floor(this.options.height * this.options.scale)
+ }
+
+ public getInnerWidth(): number {
+ const width = this.getWidth()
+ const margins = this.getMargins()
+ return width - margins[1] - margins[3]
+ }
+
+ public getMargins(): number[] {
+ return this.options.margins.map(m => m * this.options.scale)
+ }
+
+ public getPageGap(): number {
+ return this.options.pageGap * this.options.scale
+ }
+
+ public getPageNumberBottom(): number {
+ return this.options.pageNumberBottom * this.options.scale
+ }
+
+ public getMarginIndicatorSize(): number {
+ return this.options.marginIndicatorSize * this.options.scale
+ }
+
+ public getDefaultBasicRowMarginHeight(): number {
+ return this.options.defaultBasicRowMarginHeight * this.options.scale
+ }
+
public getContainer(): HTMLDivElement {
return this.container
}
@@ -222,9 +253,27 @@ export class Draw {
})
}
+ public setPageScale(payload: number) {
+ this.options.scale = payload
+ const width = this.getWidth()
+ const height = this.getHeight()
+ this.container.style.width = `${width}px`
+ this.pageList.forEach(p => {
+ p.width = width
+ p.height = height
+ p.style.width = `${width}px`
+ p.style.height = `${height}px`
+ p.style.marginBottom = `${this.getPageGap()}px`
+ })
+ this.render({ isSubmitHistory: false, isSetCursor: false })
+ if (this.listener.pageScaleChange) {
+ this.listener.pageScaleChange(payload)
+ }
+ }
+
private _createPageContainer(): HTMLDivElement {
// 容器宽度需跟随纸张宽度
- this.container.style.width = `${this.options.width}px`
+ this.container.style.width = `${this.getWidth()}px`
const pageContainer = document.createElement('div')
pageContainer.classList.add('page-container')
this.container.append(pageContainer)
@@ -232,16 +281,18 @@ export class Draw {
}
private _createPage(pageNo: number) {
+ const width = this.getWidth()
+ const height = this.getHeight()
const canvas = document.createElement('canvas')
- canvas.style.width = `${this.options.width}px`
- canvas.style.height = `${this.options.height}px`
- canvas.style.marginBottom = `${this.options.pageGap}px`
+ canvas.style.width = `${width}px`
+ canvas.style.height = `${height}px`
+ canvas.style.marginBottom = `${this.getPageGap()}px`
canvas.setAttribute('data-index', String(pageNo))
this.pageContainer.append(canvas)
// 调整分辨率
const dpr = window.devicePixelRatio
- canvas.width = parseInt(canvas.style.width) * dpr
- canvas.height = parseInt(canvas.style.height) * dpr
+ canvas.width = width * dpr
+ canvas.height = height * dpr
canvas.style.cursor = 'text'
const ctx = canvas.getContext('2d')!
ctx.scale(dpr, dpr)
@@ -250,16 +301,17 @@ export class Draw {
this.ctxList.push(ctx)
}
- private _getFont(el: IElement): string {
+ private _getFont(el: IElement, scale: number = 1): string {
const { defaultSize, defaultFont } = this.options
- return `${el.italic ? 'italic ' : ''}${el.bold ? 'bold ' : ''}${el.size || defaultSize}px ${el.font || defaultFont}`
+ return `${el.italic ? 'italic ' : ''}${el.bold ? 'bold ' : ''}${(el.size || defaultSize) * scale}px ${el.font || defaultFont}`
}
private _computeRowList() {
- const { defaultSize, defaultRowMargin, defaultBasicRowMarginHeight } = this.options
+ const { defaultSize, defaultRowMargin, scale } = this.options
+ const innerWidth = this.getInnerWidth()
+ const defaultBasicRowMarginHeight = this.getDefaultBasicRowMarginHeight()
const canvas = document.createElement('canvas')
const ctx = canvas.getContext('2d') as CanvasRenderingContext2D
- const innerWidth = this.innerWidth
const rowList: IRow[] = []
if (this.elementList.length) {
rowList.push({
@@ -281,24 +333,30 @@ export class Draw {
boundingBoxDescent: 0
}
if (element.type === ElementType.IMAGE) {
- metrics.height = element.height!
+ const elementWidth = element.width! * scale
+ const elementHeight = element.height! * scale
// 图片超出尺寸后自适应
- if (curRow.width + element.width! > innerWidth) {
+ if (curRow.width + elementWidth > innerWidth) {
// 计算剩余大小
const surplusWidth = innerWidth - curRow.width
element.width = surplusWidth
- element.height = element.height! * surplusWidth / element.width
+ element.height = elementHeight * surplusWidth / elementWidth
+ metrics.width = element.width
+ metrics.height = element.height
+ metrics.boundingBoxDescent = element.height
+ } else {
+ metrics.width = elementWidth
+ metrics.height = elementHeight
+ metrics.boundingBoxDescent = elementHeight
}
- metrics.width = element.width!
metrics.boundingBoxAscent = 0
- metrics.boundingBoxDescent = element.height!
} else {
- metrics.height = element.size || this.options.defaultSize
+ metrics.height = (element.size || this.options.defaultSize) * scale
ctx.font = this._getFont(element)
const fontMetrics = this.textParticle.measureText(ctx, element)
- metrics.width = fontMetrics.width
- metrics.boundingBoxAscent = element.value === ZERO ? defaultSize : fontMetrics.actualBoundingBoxAscent
- metrics.boundingBoxDescent = fontMetrics.actualBoundingBoxDescent
+ metrics.width = fontMetrics.width * scale
+ metrics.boundingBoxAscent = (element.value === ZERO ? defaultSize : fontMetrics.actualBoundingBoxAscent) * scale
+ metrics.boundingBoxDescent = fontMetrics.actualBoundingBoxDescent * scale
}
const ascent = metrics.boundingBoxAscent + rowMargin
const descent = metrics.boundingBoxDescent + rowMargin
@@ -306,7 +364,7 @@ export class Draw {
const rowElement: IRowElement = {
...element,
metrics,
- style: ctx.font
+ style: this._getFont(element, scale)
}
// 超过限定宽度
if (curRow.width + metrics.width > innerWidth || (i !== 0 && element.value === ZERO)) {
@@ -322,7 +380,7 @@ export class Draw {
if (curRow.height < height) {
curRow.height = height
if (element.type === ElementType.IMAGE) {
- curRow.ascent = element.height!
+ curRow.ascent = metrics.height
} else {
curRow.ascent = ascent
}
@@ -334,7 +392,9 @@ export class Draw {
}
private _drawElement(positionList: IElementPosition[], rowList: IRow[], pageNo: number) {
- const { margins, width, height } = this.options
+ const width = this.getWidth()
+ const height = this.getHeight()
+ const margins = this.getMargins()
const ctx = this.ctxList[pageNo]
ctx.clearRect(0, 0, width, height)
// 绘制背景
@@ -361,7 +421,7 @@ export class Draw {
const element = curRow.elementList[j]
const metrics = element.metrics
const offsetY = element.type === ElementType.IMAGE
- ? curRow.ascent - element.height!
+ ? curRow.ascent - metrics.height
: curRow.ascent
const positionItem: IElementPosition = {
pageNo,
@@ -430,6 +490,7 @@ export class Draw {
isSetCursor = true,
isComputeRowList = true
} = payload || {}
+ const height = this.getHeight()
// 计算行信息
if (isComputeRowList) {
this._computeRowList()
@@ -439,14 +500,14 @@ export class Draw {
this.position.setPositionList([])
const positionList = this.position.getPositionList()
// 按页渲染
- const { margins } = this.options
+ const margins = this.getMargins()
const marginHeight = margins[0] + margins[2]
let pageHeight = marginHeight
let pageNo = 0
let pageRowList: IRow[][] = [[]]
for (let i = 0; i < this.rowList.length; i++) {
const row = this.rowList[i]
- if (row.height + pageHeight > this.options.height) {
+ if (row.height + pageHeight > height) {
pageHeight = marginHeight + row.height
pageRowList.push([row])
pageNo++
diff --git a/src/editor/core/draw/frame/Margin.ts b/src/editor/core/draw/frame/Margin.ts
index c361fbc..ff2953c 100644
--- a/src/editor/core/draw/frame/Margin.ts
+++ b/src/editor/core/draw/frame/Margin.ts
@@ -3,15 +3,20 @@ import { Draw } from "../Draw"
export class Margin {
+ private draw: Draw
private options: Required
constructor(draw: Draw) {
+ this.draw = draw
this.options = draw.getOptions()
}
public render(ctx: CanvasRenderingContext2D) {
- const { width, height } = this.options
- const { marginIndicatorColor, marginIndicatorSize, margins } = this.options
+ const { marginIndicatorColor } = this.options
+ const width = this.draw.getWidth()
+ const height = this.draw.getHeight()
+ const margins = this.draw.getMargins()
+ const marginIndicatorSize = this.draw.getMarginIndicatorSize()
ctx.save()
ctx.strokeStyle = marginIndicatorColor
ctx.beginPath()
diff --git a/src/editor/core/draw/frame/PageNumber.ts b/src/editor/core/draw/frame/PageNumber.ts
index 4cda3f7..d6ca451 100644
--- a/src/editor/core/draw/frame/PageNumber.ts
+++ b/src/editor/core/draw/frame/PageNumber.ts
@@ -3,17 +3,22 @@ import { Draw } from "../Draw"
export class PageNumber {
+ private draw: Draw
private options: Required
constructor(draw: Draw) {
+ this.draw = draw
this.options = draw.getOptions()
}
public render(ctx: CanvasRenderingContext2D, pageNo: number) {
- const { pageNumberBottom, width, height } = this.options
+ const { pageNumberSize, pageNumberFont, scale } = this.options
+ const width = this.draw.getWidth()
+ const height = this.draw.getHeight()
+ const pageNumberBottom = this.draw.getPageNumberBottom()
ctx.save()
ctx.fillStyle = '#00000'
- ctx.font = '12px'
+ ctx.font = `${pageNumberSize * scale}px ${pageNumberFont}`
ctx.fillText(`${pageNo + 1}`, width / 2, height - pageNumberBottom)
ctx.restore()
}
diff --git a/src/editor/core/draw/particle/ImageParticle.ts b/src/editor/core/draw/particle/ImageParticle.ts
index 39f939b..3225684 100644
--- a/src/editor/core/draw/particle/ImageParticle.ts
+++ b/src/editor/core/draw/particle/ImageParticle.ts
@@ -72,7 +72,9 @@ export class ImageParticle {
private _handleMousedown(evt: MouseEvent) {
this.canvas = this.draw.getPage()
if (!this.curPosition || !this.curElement) return
- const { height, pageGap } = this.options
+ const { scale } = this.options
+ const height = this.draw.getHeight()
+ const pageGap = this.draw.getPageGap()
this.mousedownX = evt.x
this.mousedownY = evt.y
const target = evt.target as HTMLDivElement
@@ -88,8 +90,8 @@ export class ImageParticle {
const prePageHeight = this.draw.getPageNo() * (height + pageGap)
this.resizerImageContainer.style.left = `${left}px`
this.resizerImageContainer.style.top = `${top + prePageHeight}px`
- this.resizerImage.style.width = `${this.curElement.width}px`
- this.resizerImage.style.height = `${this.curElement.height}px`
+ this.resizerImage.style.width = `${this.curElement.width! * scale}px`
+ this.resizerImage.style.height = `${this.curElement.height! * scale}px`
// 追加全局事件
const mousemoveFn = this._mousemove.bind(this)
document.addEventListener('mousemove', mousemoveFn)
@@ -114,6 +116,7 @@ export class ImageParticle {
private _mousemove(evt: MouseEvent) {
if (!this.curElement) return
+ const { scale } = this.options
let dx = 0
let dy = 0
switch (this.curHandleIndex) {
@@ -148,8 +151,8 @@ export class ImageParticle {
}
this.width = this.curElement.width! + dx
this.height = this.curElement.height! + dy
- this.resizerImage.style.width = `${this.width}px`
- this.resizerImage.style.height = `${this.height}px`
+ this.resizerImage.style.width = `${this.width * scale}px`
+ this.resizerImage.style.height = `${this.height * scale}px`
evt.preventDefault()
}
@@ -158,36 +161,39 @@ export class ImageParticle {
}
public drawResizer(element: IElement, position: IElementPosition) {
+ const { scale } = this.options
const { coordinate: { leftTop: [left, top] } } = position
- const width = element.width!
- const height = element.height!
+ const elementWidth = element.width! * scale
+ const elementHeight = element.height! * scale
+ const height = this.draw.getHeight()
+ const pageGap = this.draw.getPageGap()
const handleSize = this.options.resizerSize
- const preY = this.draw.getPageNo() * (this.options.height + this.options.pageGap)
+ const preY = this.draw.getPageNo() * (height + pageGap)
// 边框
this.resizerSelection.style.left = `${left}px`
this.resizerSelection.style.top = `${top + preY}px`
- this.resizerSelection.style.width = `${element.width}px`
- this.resizerSelection.style.height = `${element.height}px`
+ this.resizerSelection.style.width = `${elementWidth}px`
+ this.resizerSelection.style.height = `${elementHeight}px`
// handle
for (let i = 0; i < 8; i++) {
const left = i === 0 || i === 6 || i === 7
? -handleSize
: i === 1 || i === 5
- ? width / 2
- : width - handleSize
+ ? elementWidth / 2
+ : elementWidth - handleSize
const top = i === 0 || i === 1 || i === 2
? -handleSize
: i === 3 || i === 7
- ? height / 2 - handleSize
- : height - handleSize
+ ? elementHeight / 2 - handleSize
+ : elementHeight - handleSize
this.resizerHandleList[i].style.left = `${left}px`
this.resizerHandleList[i].style.top = `${top}px`
}
this.resizerSelection.style.display = 'block'
this.curElement = element
this.curPosition = position
- this.width = this.curElement.width!
- this.height = this.curElement.height!
+ this.width = this.curElement.width! * scale
+ this.height = this.curElement.height! * scale
}
public clearResizer() {
@@ -195,8 +201,9 @@ export class ImageParticle {
}
public render(ctx: CanvasRenderingContext2D, element: IElement, x: number, y: number) {
- const width = element.width!
- const height = element.height!
+ const { scale } = this.options
+ const width = element.width! * scale
+ const height = element.height! * scale
if (this.imageCache.has(element.id!)) {
const img = this.imageCache.get(element.id!)!
ctx.drawImage(img, x, y, width, height)
diff --git a/src/editor/core/listener/Listener.ts b/src/editor/core/listener/Listener.ts
index a4bb989..23d257d 100644
--- a/src/editor/core/listener/Listener.ts
+++ b/src/editor/core/listener/Listener.ts
@@ -1,5 +1,6 @@
import {
IIntersectionPageNoChange,
+ IPageScaleChange,
IPageSizeChange,
IRangeStyleChange,
IVisiblePageNoListChange
@@ -11,12 +12,14 @@ export class Listener {
public visiblePageNoListChange: IVisiblePageNoListChange | null
public intersectionPageNoChange: IIntersectionPageNoChange | null
public pageSizeChange: IPageSizeChange | null
+ public pageScaleChange: IPageScaleChange | null
constructor() {
this.rangeStyleChange = null
this.visiblePageNoListChange = null
this.intersectionPageNoChange = null
this.pageSizeChange = null
+ this.pageScaleChange = null
}
}
\ No newline at end of file
diff --git a/src/editor/index.ts b/src/editor/index.ts
index 001fd6d..a748ab6 100644
--- a/src/editor/index.ts
+++ b/src/editor/index.ts
@@ -24,8 +24,11 @@ export default class Editor {
defaultBasicRowMarginHeight: 8,
width: 794,
height: 1123,
+ scale: 1,
pageGap: 20,
pageNumberBottom: 60,
+ pageNumberSize: 12,
+ pageNumberFont: 'Yahei',
underlineColor: '#000000',
strikeoutColor: '#FF0000',
rangeAlpha: 0.6,
diff --git a/src/editor/interface/Editor.ts b/src/editor/interface/Editor.ts
index e02b47c..872d3bf 100644
--- a/src/editor/interface/Editor.ts
+++ b/src/editor/interface/Editor.ts
@@ -6,8 +6,11 @@ export interface IEditorOption {
defaultRowMargin?: number;
width?: number;
height?: number;
+ scale?: number;
pageGap?: number;
pageNumberBottom?: number;
+ pageNumberSize?: number;
+ pageNumberFont?: string;
underlineColor?: string;
strikeoutColor?: string;
rangeColor?: string;
diff --git a/src/editor/interface/Listener.ts b/src/editor/interface/Listener.ts
index f0ca881..8f16c30 100644
--- a/src/editor/interface/Listener.ts
+++ b/src/editor/interface/Listener.ts
@@ -22,3 +22,5 @@ export type IVisiblePageNoListChange = (payload: number[]) => void
export type IIntersectionPageNoChange = (payload: number) => void
export type IPageSizeChange = (payload: number) => void
+
+export type IPageScaleChange = (payload: number) => void
diff --git a/src/main.ts b/src/main.ts
index ca5fbc9..e3ee5f0 100644
--- a/src/main.ts
+++ b/src/main.ts
@@ -231,6 +231,14 @@ window.onload = function () {
console.log('print')
instance.command.executePrint()
}
+ document.querySelector('.page-scale-minus')!.onclick = function () {
+ console.log('page-scale-minus')
+ instance.command.executePageScaleMinus()
+ }
+ document.querySelector('.page-scale-add')!.onclick = function () {
+ console.log('page-scale-add')
+ instance.command.executePageScaleAdd()
+ }
// 内部事件监听
instance.listener.rangeStyleChange = function (payload) {
@@ -295,4 +303,8 @@ window.onload = function () {
document.querySelector('.page-no')!.innerText = `${payload + 1}`
}
+ instance.listener.pageScaleChange = function (payload) {
+ document.querySelector('.page-scale-percentage')!.innerText = `${Math.floor(payload * 100)}%`
+ }
+
}
\ No newline at end of file
diff --git a/src/style.css b/src/style.css
index 047d19a..328832e 100644
--- a/src/style.css
+++ b/src/style.css
@@ -395,11 +395,14 @@ ul {
cursor: pointer;
}
-.footer>div:last-child .page-minus {
- background-image: url('./assets/images/page-minus.svg');
+.footer .page-scale-minus i {
+ background-image: url('./assets/images/page-scale-minus.svg');
+}
+.footer .page-scale-add i {
+ background-image: url('./assets/images/page-scale-add.svg');
}
-.footer>div:last-child .page-add {
- background-image: url('./assets/images/page-add.svg');
+.footer .page-scale-percentage {
+ user-select: none;
}
\ No newline at end of file